В настоящее время я поддерживаю C++ REST Server, разработанный на C++. Он предоставляет некоторые функции, такие как промежуточное ПО и маршруты.
Маршруты хранятся во внутренней структуре класса маршрутизатора:
//! The http router
//!
//! allow us to parse route on a server using regex to match the good route for a given url
//! and extract the possible url variables
class router {
private:
//! routes datas
//!
//! contains:
//! * the regex to parse the routes
//! * an std::vector with the list of variable inside the routes
//! * 4 std::function, one for each REST methods
struct rest_routes {
std::regex regex;
std::vector<std::string> vars_name;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> get;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> post;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> put;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> del;
};
};
Во время выполнения все работает хорошо: маршруты можно настроить и добавить в маршрутизатор, и если кто-то запрашивает сервер по существующему маршруту, выполняется обратный вызов, и сервер отправляет ответ, как и ожидалось.
Вот пример конфигурации маршрута, где мы создаем маршрут /admin/cameras/:cam_id
для запроса HTTP DELETE
:
// delete a camera
router.del("/admin/cameras/:cam_id",
std::bind(&admin_service::remove_camera, service, std::placeholders::_1));
В этом примере admin_service::remove_camera
— это функция-член, а service
— это shared_ptr
содержащий указатель на admin_service
объект. Если кто-то запрашивает этот маршрут, вызывается admin_service::remove_camera
.
Однако сервер segfaults в конце выполнения (когда мы выходим из сервера).
Я проследил происхождение segfault, и он исходит от деструктора... std::function
. Точнее, это произошло во время уничтожения одного из std::function
, содержащихся в std::pair
с get
, post
, put
и del
.
Я могу сказать это, потому что, когда я помещаю следующий код отладки:
struct rest_routes {
~rest_routes() {
std::cout << "BEGIN DTOR rest_routes" << std::endl;
std::cout << "BEGIN get" << std::endl;
get.first = nullptr;
std::cout << "END get" << std::endl;
std::cout << "BEGIN post" << std::endl;
post.first = nullptr;
std::cout << "END post" << std::endl;
std::cout << "BEGIN put" << std::endl;
put.first = nullptr;
std::cout << "END put" << std::endl;
std::cout << "BEGIN del" << std::endl;
del.first = nullptr;
std::cout << "END del" << std::endl;
std::cout << "END DTOR rest_routes" << std::endl;
}
std::regex regex;
std::vector<std::string> vars_name;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> get;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> post;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> put;
std::pair<std::function<http::response(http::request&)>, std::vector<std::string>> del;
};
Я получил следующий вывод:
BEGIN DTOR rest_routes
BEGIN get
END get
BEGIN post
END post
BEGIN put
END put
BEGIN del
Segmentation Fault
Я не могу понять, как std::function может segfault во время уничтожения или назначения...
Сначала я подумал, что, может быть, std::function
взял ссылку на std::shared_ptr service
вместо того, чтобы брать его по значению, и удалил необработанный указатель, который он содержит, более одного раза. Но когда я помещаю отладочный вывод, я вижу, что счетчик shared_ptr
увеличивается после вызова router.del
.
Есть ли у кого-нибудь идеи по этому вопросу?
I can't figure how a std::function can segfault during destruction or assignment
Сделайте еще один шаг и изолируйте строку кода или шаг, вызвавший segfault в деструкторе. Затем используйте это как отправную точку. - person PaulMcKenzie   schedule 17.04.2015std::function
(del.first = nullptr
). Это вызывает segfault во время назначения. Этот вызов оператора присваивания может иметь некоторые операции, аналогичные операциям деструктора (например, удаление внутренних атрибутов). Но теперь у меня есть идея, как пойти дальше, кроме как открыть исходный код стандартной библиотеки. - person Simon Ninon   schedule 17.04.2015std::function
вместоshared_ptr
. Вот так... std::bind( &admin_service::remove_camera, service.get(), std::placeholders::_1)
- person borisbn   schedule 17.04.2015std::bind(&admin_service::remove_camera, *(service.get()), std::placeholders::_1)
), но ошибка сегментации продолжает происходить в том же месте. И, очевидно, когда я удаляю конфигурацию маршрутов, программа завершается правильно. - person Simon Ninon   schedule 17.04.2015del
все еще действителен? Это единственный способ увидеть, где произойдет сбой присваивания указателя, и это базовый объект, содержащий указатель, недействителен. - person PaulMcKenzie   schedule 17.04.2015