Socket读取访问违例:异步写入触发0xc0000005错误求助
Socket异步写入触发内存访问错误的排查与解决
问题场景
使用Boost.Asio进行Socket第二次异步写入时,触发读取访问违例错误(错误代码0xc0000005,错误地址0xffffffffffffffff),程序跳转至xmemory文件的迭代器处理代码段。
相关发送代码
void ClientWindow::on_button_send_clicked() { auto message = std::make_shared<std::string>(ui->plainTextEdit->toPlainText().toStdString()); auto message_size = std::make_shared<short>(static_cast<short>(message->size())); if(*message_size==0) return; _socket.async_write_some(boost::asio::buffer(message_size.get(),sizeof(*message_size)), [this,message](const boost::system::error_code& error, std::size_t) { if(!error){ emit clearPlainTextEdit(); qDebug()<<message->size(); qDebug()<<*message; _socket.async_write_some(boost::asio::buffer(message->data(),message->size()), [this](const boost::system::error_code& error, std::size_t) { if(error) emit settingStatusBarMessage(error.message() + ": sending size of message error"); }); }else emit settingStatusBarMessage(error.message() + ": sending message error"); }); }
触发错误的xmemory代码片段
for (auto _Pnext = _STD exchange(_Myproxy->_Myfirstiter, nullptr); _Pnext; _Pnext = _Pnext->_Mynextiter) { _Pnext->_Myproxy = nullptr; }
已尝试的操作
- 在lambda中按值捕获
std::shared_ptr确保对象生命周期 - 提前检查消息内容和大小
- 改用对象属性替代智能指针,问题依旧
问题根源分析
内层lambda未捕获
message导致内存提前释放:
外层lambda捕获了message,但内层lambda仅捕获this。当外层lambda发起第二个异步写入后立即执行完毕,message的引用计数减1,若没有其他持有者,std::string对象会被销毁,而后台异步写入操作仍在访问已释放的内存,触发访问违例。async_write_some的使用误区:
该函数仅保证写入部分数据就触发handler,无法确保完整发送消息,可能导致后续逻辑混乱,不适合需要完整传输数据的场景。潜在的对象生命周期风险:
若ClientWindow或_socket在异步操作执行期间被销毁,也会导致野指针访问错误。
解决方案
1. 内层lambda捕获message
确保第二个异步写入操作期间,message的生命周期被延长,避免内存提前释放:
_socket.async_write_some(boost::asio::buffer(message->data(), message->size()), [this, message](const boost::system::error_code& error, std::size_t) { if(error) emit settingStatusBarMessage(error.message() + ": sending message content error"); });
2. 改用async_write替代async_write_some
async_write会保证将整个buffer的数据发送完成才触发handler,更适合完整传输数据的场景:
// 发送消息长度 boost::asio::async_write(_socket, boost::asio::buffer(message_size.get(), sizeof(*message_size)), [this, message](const boost::system::error_code& error, std::size_t) { if(!error){ emit clearPlainTextEdit(); qDebug()<<message->size(); qDebug()<<*message; // 发送消息内容 boost::asio::async_write(_socket, boost::asio::buffer(message->data(), message->size()), [this, message](const boost::system::error_code& error, std::size_t) { if(error) emit settingStatusBarMessage(error.message() + ": sending message content error"); }); }else emit settingStatusBarMessage(error.message() + ": sending message size error"); });
3. 确保ClientWindow生命周期覆盖异步操作
让ClientWindow继承std::enable_shared_from_this,通过捕获shared_ptr避免对象被提前销毁:
// 类定义修改 class ClientWindow : public QMainWindow, public std::enable_shared_from_this<ClientWindow> { // ... 原有成员 }; // 修改lambda捕获逻辑 _socket.async_write_some(boost::asio::buffer(message_size.get(), sizeof(*message_size)), [self = shared_from_this(), message](const boost::system::error_code& error, std::size_t) { if(!error){ emit self->clearPlainTextEdit(); qDebug()<<message->size(); qDebug()<<*message; self->_socket.async_write_some(boost::asio::buffer(message->data(), message->size()), [self, message](const boost::system::error_code& error, std::size_t) { if(error) emit self->settingStatusBarMessage(error.message() + ": sending message content error"); }); }else emit self->settingStatusBarMessage(error.message() + ": sending message size error"); });
验证步骤
- 先修改内层lambda捕获
message,测试是否消除内存错误 - 若问题解决,替换为
async_write优化发送逻辑 - 最后检查对象生命周期,确保异步操作期间相关对象未被销毁
内容的提问来源于stack exchange,提问作者Danek
相关产品推荐
相关产品推荐

