强制 boost::asio::buffer 以值的方式复制

10
我使用boost::asio::buffer发送消息。
void Send(const std::string& messageData)
{
    socket.async_write(boost::asio::buffer(messageData), ...);
}

我在io_service的线程中遇到了“string iterator not dereferencable”的运行时错误。当我创建对象变量来存储缓冲区的消息数据时:

void Send(const std::string& messageData)
{
    this->tempStorage = messageData;
    socket.async_write(boost::asio::buffer(this->tempStorage), ...);
}

错误从未发生过。 std::string(messageData所引用的内容)在调用Send()后几乎立即被释放 - boost :: asio :: buffer是否仅存储对对象的引用? 如果是这样,我该如何强制它按值存储数据?

2个回答

16

来自boost-users邮件列表的回答:

如果它这样做,那么它将是完全无用的,因为您无法访问完成处理程序中的任何缓冲区。

使用buffer()的方法是传递对存储的引用,您保证以其他方式保持其生命周期。

您可以将其存储在外部对象中,或者像您所做的那样将其存储在`this'中,或者通过将其绑定到完成处理程序函数对象本身中。

void onComplete(shared_ptr<std::string> s, error_code const&, size_t)
{
    // do stuff
}

void send(std::string const& messageData)
{
    shared_ptr<std::string> s = make_shared<std::string>(messageData);
    async_send(socket, boost::asio::buffer(*s),
    boost::bind(&T::onSend, this, s, _1, _2));
}

这确保了缓冲数据的生命周期至少与完成处理程序的存在时间一样长。

1
async_send 在 C++11 中可以稍微缩短一下,如果我说错了,请纠正: async_send(socket, boost::asio::buffer(*s), [s](error_code const&, size_t) {});。现在不需要创建类成员函数 onComplete 了。 - Tsar Ioann
@slav 在这里不需要一个字符串指针,因为字符串本身管理堆上数据的分配。 - Francisco Aguilera
@FranciscoAguilera 你所指的确切 指针 是什么?如果是 shared_ptr,那么在 void send() 结束时,没有它 std::string 将会被销毁(以及所有在堆上分配的动态数据将被释放)。 - Slaus
有没有办法使用unique_ptr将其绑定到完成处理程序?应该有吧?与相对较慢的shared_ptr相比,这将对性能产生积极影响。 - Kenji
@Kenji:很遗憾,不行。你可以将unique_ptr移动捕获到lambda中(从C++14开始),但这会使lambda本身无法复制,违反了boost::asio要求处理程序可拷贝构造的规定。 - sh-

1

来自 boost::asio 的文档:

缓冲区对象不具有所引用内存的所有权。应用程序有责任确保在 I/O 操作需要之前,内存区域保持有效。当内存不再可用时,缓冲区被认为已失效。

对于接受类型为 std::vector 参数的 boost::asio::buffer 重载函数,由任何使得序列中所有引用、指针和迭代器都失效的向量操作所产生的缓冲区对象也将失效(C++ 标准,23.2.4)。

对于接受类型为 std::basic_string 参数的 boost::asio::buffer 重载函数,生成的缓冲区对象将根据引用、指针和迭代器指向序列元素的失效规则而失效(C++ 标准,21.3)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接