删除含boost::scoped_ptr socket成员的对象时程序崩溃如何解决
问题根因
崩溃的核心原因是 boost::asio::io_context 生命周期短于关联的socket生命周期:
你在connect方法内部将io_context定义为栈局部变量,connect执行完成返回后,这个io_context就会被栈释放销毁,但你创建的signal_socket仍然持有该已销毁io_context的引用。后续调用disconnect执行socket的shutdown、close操作,或者socket析构时,都会访问已经失效的内存,触发未定义行为导致程序崩溃。这也符合你给出的日志特征:执行到HEY4 VAL 1之后,调用disconnect时直接崩溃,所以后续的HEY5和boost.test的测试汇总都没有输出。
同时你代码还存在几个额外的错误点:
- 客户端socket构造时不需要传入endpoint,你当前代码
socket(io_context, signal_endpoint)是将socket绑定到对应端口,属于服务端逻辑,客户端仅需要传入io_context即可,后续主动调用connect连接目标地址。 - 第一个测试用例
basis_constructor_test的校验逻辑错误:构造函数里初始化state为CL_UNCON,但测试用例判断等于CL_READY,该用例本身就无法通过。 disconnect里的shutdown、close调用没有捕获错误或传入error_code参数,若socket已经处于半关闭状态,调用这两个接口会直接抛出异常导致程序终止。
修复步骤
- 将
io_context改为SimpleClient类的成员变量,保证其生命周期和signal_socket完全一致:
class SimpleClient{ private: boost::asio::io_context io_context; // 新增成员变量 boost::scoped_ptr<boost::asio::ip::tcp::socket> signal_socket; protected: ClientState state; // 其余接口保持不变 };
- 修改
connect方法里的socket构造逻辑,移除构造时传入的endpoint参数:
// 原代码:signal_socket.reset(new boost::asio::ip::tcp::socket(io_context, signal_endpoint)); // 修改为: signal_socket.reset(new boost::asio::ip::tcp::socket(io_context));
- 修改
disconnect方法,增加错误码参数避免异常抛出:
void SimpleClient::disconnect() { if(signal_socket!=NULL && signal_socket->is_open()) { boost::system::error_code ec; signal_socket->shutdown(boost::asio::socket_base::shutdown_both, ec); // 忽略shutdown错误,继续执行close signal_socket->close(ec); signal_socket.reset(); } state = ClientState::CL_UNCON; }
- 修正第一个测试用例的校验逻辑,和构造函数的初始化值对齐。
完成上述修改后,socket关联的io_context在对象销毁前始终有效,就不会出现访问失效内存的崩溃问题了。
内容的提问来源于stack exchange,提问作者Gionata Benelli
相关产品推荐
相关产品推荐

