#c #boost-asio
#c #увеличить-asio
Вопрос:
Я использую boost::asio::buffer для отправки сообщения с использованием
void Send(const std::stringamp; messageData)
{
socket.async_write(boost::asio::buffer(messageData), ...);
}
И сталкиваемся с ошибкой времени выполнения «строковый итератор не разыменовывается» где-то в потоке io_service. Когда я создаю переменную объектов для хранения данных сообщения для буфера:
void Send(const std::stringamp; messageData)
{
this->tempStorage = messageData;
socket.async_write(boost::asio::buffer(this->tempStorage), ...);
}
ошибка никогда не возникала.
std::string (на который ссылается MessageData) освобождается почти сразу после вызова Send() — хранит ли boost::asio::buffer только ссылку на объект?
Если да, то как я могу заставить его сохранять данные по значению?
Ответ №1:
Ответ из списков рассылки boost-пользователей:
Если бы это произошло, это было бы совершенно бесполезно, поскольку у вас нет доступа ни к одному из буферов в вашем обработчике завершения.
Способ использования buffer() заключается в передаче ссылок на хранилище, срок службы которого вы гарантируете каким-либо другим способом.
Вы можете либо сохранить его во внешнем объекте, либо сохранить его в `this’, как вы это делали, либо привязав его к самому объекту функции обработчика завершения.
void onComplete(shared_ptr<std::string> s, error_code constamp;, size_t)
{
// do stuff
}
void send(std::string constamp; messageData)
{
shared_ptr<std::string> s = make_shared<std::string>(messageData);
async_send(socket, boost::asio::buffer(*s),
boost::bind(amp;T::onSend, this, s, _1, _2));
}
Это гарантирует, что время жизни данных в буфере будет по крайней мере таким же, как
обработчик завершения существует.
Комментарии:
1.
async_send
вызов может быть немного сокращен в C 11, пожалуйста, поправьте меня, если я ошибаюсь:async_send(socket, boost::asio::buffer(*s), [s](error_code constamp;, size_t) {});
. И теперь нет необходимости создавать функцию-член классаonComplete
.2. @slav здесь вам не нужен указатель на строку, строка сама управляет распределением данных в куче.
3. @FranciscoAguilera какой именно указатель вы имеете в виду? Если это shared_ptr , то без этого std::string будет уничтожен (и все его динамические данные, размещенные в куче, будут освобождены) в конце
void send()
.4. Есть ли способ привязать его к обработчику завершения с помощью
unique_ptr
? Должно быть, верно? Это оказало бы положительное влияние на производительность, по сравнению сshared_ptr
которая довольно медленная.5. @Kenji: К сожалению, нет. Вы могли бы переместить-захватить unique_ptr в лямбда-выражение (начиная с C 14), но это сделало бы само лямбда-выражение недоступным для копирования, что нарушает требование boost:: asio о том, что обработчик должен быть сконструирован для копирования.
Ответ №2:
Объект buffer не имеет права собственности на память, на которую он ссылается. Приложение несет ответственность за то, чтобы область памяти оставалась действительной до тех пор, пока она больше не потребуется для операции ввода-вывода. Когда память больше не доступна, буфер считается недействительным.
При
boost::asio::buffer
перегрузках, которые принимают аргумент типаstd::vector
, возвращаемые объекты буфера становятся недействительными в результате любой векторной операции, которая также делает недействительными все ссылки, указатели и итераторы, ссылающиеся на элементы в последовательности (C Std, 23.2.4)При
boost::asio::buffer
перегрузках, которые принимают аргумент типаstd::basic_string
, возвращаемые объекты буфера признаются недействительными в соответствии с правилами, определенными для признания недействительными ссылок, указателей и итераторов, ссылающихся на элементы последовательности (C Std, 21.3).