Ошибка EXC_BAD_ACCESS при использовании обратного вызова Lambda в клиенте C++ SocketIOC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Ошибка EXC_BAD_ACCESS при использовании обратного вызова Lambda в клиенте C++ SocketIO

Сообщение Anonymous »


Я разрабатываю класс на C++, который включает обработку событий SocketIO. Класс содержит метод, который привязывает событие к функции с помощью лямбды. Эта лямбда фиксирует this в конструкторе класса. Однако при выполнении обратного вызова возникает ошибка EXC_BAD_ACCESS. Похоже, проблема связана именно с захватом this.

У меня есть класс Queue, в котором я регистрирую обратные вызовы для событий SocketIO. Я использую лямбду для обработки этих событий и внутри этой лямбды фиксирую это. Кажется, ошибка возникает при вызове обратного вызова. Сегодня конструктор класса на самом деле выглядит следующим образом:

Queue::Queue(const std::string &node_name, std::unique_ptr sio_client) : rclcpp::Node(node_name), node_name_(node_name) , robot_status_(RobotStatus::NOT_INITIALIZED), sio_client(std::move(sio_client)) { this->queue_ = std::vector(); this->timer_ = this->create_wall_timer(std::chrono::milliсекунды(300), std::bind(&Queue::timer_callback_, this)); // Подписчики enqueue_subscription_ = this->create_subscription( "enqueue", 10, std::bind(&Queue::enqueue_callback_, this, std::placeholders::_1)); status_subscription_ = this->create_subscription( "status", 10, std::bind(&Queue::status_callback_, this, std::placeholders::_1)); // Пабы dequeue_publisher_ = this->create_publisher("dequeue", 10); log_publisher_ = this->create_publisher("log", 10); // Слушатели событий SIO this->sio_client->client->socket()->on( "/поставить в очередь", sio::socket::event_listener_aux([&](std::string const &name, sio::message::ptr const &data, логический isAck, sio::message::list &ack_resp) { это->on_sio_enqueue_(данные); })); } И функция, которую я вызываю внутри лямбда-функции, выглядит следующим образом:

void Queue::on_sio_enqueue_(const std::shared_ptr &data) { пытаться { json parsedData = json::parse(data->get_string()); auto x = parsedData.at("x").get(); auto y = parsedData.at("y").get(); RCLCPP_INFO(this->get_logger(), "Полученная поза: (%f, %f)", x, y); geometry_msgs::msg::Pose::SharedPtr поза = std::make_shared(); поза->position.x = x; поза->position.y = y; это->enqueue_callback_(поза); } catch (const std::Exception &e) { RCLCPP_ERROR(this->get_logger(), «Ошибка обратного вызова: %s», e.what()); auto info = this->generate_log_("ОШИБКА: " + std::string(e.what())); это->log_publisher_->публиковать(информация); } } А заголовочный файл класса ClientStreamer выглядит так:

с использованием json = nlohmann::json; // ЗАДАЧА: удалить наследование Node класс ClientStreamer: public rclcpp::Node { публика: typedef std::function callback_json; явный ClientStreamer(); Переопределение ~ClientStreamer(); void on_JSON(const std::string &event, const callback_json &callback); клиент std::unique_ptr; частный: станд::мьютекс _lock; std::condition_variable_any _cond; боул _connect_finish; недействительный on_connected_(); void on_close_(sio::client::close_reason const &reason); недействительный on_fail_(); voidemit_(const std::string &topic, const std::string &message); void on_message_(const std::string &name, sio::message::ptr const &data, bool isAck, sio::message::list &ack_resp); }; Но, как вы можете видеть, этот подход использует свойство client, которое я собираюсь сделать частным. Поэтому я создал метод с именем on_JSON. Этот метод не только упрощает процесс привязки событий к функциям обратного вызова, но также позволяет мне превратить client в частное свойство.

Вот упрощенная версия моего класса — метод on_JSON:

void ClientStreamer::on_JSON(const std::string &event, callback_json const &callback) { this->_client->socket()->on(event, sio::socket::event_listener_aux( [&](std::string const &name, sio::message::ptr const &data, bool isAck, sio::message::list &ack_resp) { // Обработка события и вызов обратного вызова с передачей JSON в правильной форме // *Просто пример* обратный вызов(json::parse(data->get_string()); })); } А вот как я попытался перепроектировать свой конструктор:

Queue::Queue(const std::string &node_name, std::unique_ptr sio_client) : rclcpp::Node(node_name), node_name_(node_name) , robot_status_(RobotStatus::NOT_INITIALIZED), // предыдущий код // Слушатели событий SIO это->sio_client->on_JSON( "/поставить в очередь", [&](const json& данные) { // обработка данных }); } Проблема возникает при вызове функции обратного вызова (переданной в on_JSON). Кажется, это вызывает ошибку EXC_BAD_ACCESS. Лямбда-функция фиксирует этот указатель, и я подозреваю, что проблема связана с тем, как он фиксируется и используется в лямбда-функции.

В исходном коде, который я представил ранее, конструктор в настоящее время работает правильно. Однако при моем упрощенном подходе возникает проблема: когда дело доходит до выполнения обратного вызова, возникает ошибка EXC_BAD_ACCESS. Интересно, что он даже не использует функцию обратного вызова, также известную как лямбда-функция.

Первое, что я сделал, — это правильное управление жизненным циклом задействованных объектов. sio_client_ — это std::unique_ptr внутри класса, поэтому он должен быть активным, пока существует экземпляр класса.

Более того, я удалил контекст, который получает лямбда-функция, и код работает нормально (в моем случае я не могу удалить &, поскольку мой обратный вызов зависит от this). Я мог получить доступ к данным, распечатать их, все работало нормально.

Более того, я удалил контекст, к которому обращалась лямбда-функция, и код работал нормально. После внесения этой настройки я смог получить доступ к данным и распечатать их без каких-либо проблем (я не могу удалить &, потому что мой обратный вызов зависит от this, это была всего лишь проверка чтобы проверить, является ли & проблемой на самом деле).

Итак, мои вопросы:
[*]Может ли способ, которым это фиксируется в лямбда-функции, вызывать ошибку EXC_BAD_ACCESS? [*]Есть ли что-то особенное в том, как on_JSON обрабатывает лямбда-функцию, что может привести к этой проблеме? [*]Чем подход, использующий сам клиент, отличается от подхода on_JSON?
Мы будем очень признательны за любые идеи, предложения или альтернативные подходы к отладке или решению этой проблемы.
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»