You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

unique_ptr重置时构造先于析构?是否正常或Boost日志延迟?

关于boost::movelib::unique_ptr重置时构造先于析构的疑问

问题背景

你维护着一个存储boost::movelib::unique_ptr<eth_socket>的std::vector,在第二次调用reset()时发现日志里新对象的构造函数先执行,旧对象的析构函数才跟进,疑惑这是正常行为还是Boost日志存在延迟问题。

你的伪代码如下:

std::vector <boost::movelib::unique_ptr<eth_socket> > _eth_socket_vect;
_eth_socket_vect.resize(1);
_eth_socket_vect.at(0).reset(new eth_socket(host, port, delimiter, timeout, 1)); // 首次reset无旧对象,无析构日志
// 执行一些操作,然后重置
_eth_socket_vect.at(0).reset(new eth_socket(host, port, delimiter, timeout, 1)); // 第二次reset出现构造先于析构的日志

对应的第二次reset日志:

20-02-28 08:44:14.312702 [info] src/eth_socket.cpp(eth_socket:10) >> started; host_num = 1 <---CONSTRUCTOR
20-02-28 08:44:14.312825 [info] src/eth_socket.cpp(open_eth_socket:67) >> started; host_num = 0
20-02-28 08:44:14.312869 [info] src/eth_socket.cpp(open_eth_socket:71) >> socket_host = 10.0.0.4; socket_port = 1337; host_num = 0
20-02-28 08:44:14.313016 [info] src/eth_socket.cpp(open_eth_socket:104) >> ended; host_num = 0
20-02-28 08:44:14.313054 [info] src/eth_socket.cpp(read_data:247) >> started; host_num = 0
20-02-28 08:44:14.313089 [info] src/eth_socket.cpp(read_data:275) >> ended; host_num = 0
20-02-28 08:44:14.313109 [info] src/eth_socket.cpp(eth_socket:38) >> ended; host_num = 1
20-02-28 08:44:14.313132 [info] src/eth_socket.cpp(~eth_socket:43) >> started; host_num = 0 <-- DESTRUCTOR
20-02-28 08:44:14.313225 [info] src/eth_socket.cpp(close_eth_socket:113) >> started; host_num = 0
20-02-28 08:44:14.313287 [info] src/eth_socket.cpp(socket_read_data_callback:368) >> started; host_num = 0
20-02-28 08:44:14.313299 [info] src/eth_socket.cpp(close_eth_socket:144) >> ended; host_num = 0
20-02-28 08:44:14.313327 [info] src/eth_socket.cpp(~eth_socket:58) >> ended; host_num = 0

解答:这是完全正常的行为,和Boost日志无关

要理解这个顺序,得拆解reset(new eth_socket(...))的执行步骤:

  • 第一步:先执行函数参数求值:在调用unique_ptr::reset()函数之前,new eth_socket(...)这个表达式会先被执行——也就是新的eth_socket对象会先完成构造,同时输出构造相关的日志。
  • 第二步:进入reset函数逻辑:把新对象的指针传递给reset后,函数才会处理旧对象:先保存内部的旧指针,更新内部指针指向新对象,最后才删除旧指针指向的对象,触发旧对象的析构函数并输出相关日志。

简单来说,参数里的new操作是在reset函数执行前完成的,所以必然会看到新对象构造日志先出现,旧对象析构日志在后,这是C++函数调用的基本规则,和Boost日志的延迟没有关系。

如果想避免这种“先构造新对象再析构旧对象”的顺序(比如旧对象占用资源较大,希望先释放再创建新对象),可以拆分操作:

// 先手动释放旧对象
_eth_socket_vect.at(0).reset();
// 再创建新对象
_eth_socket_vect.at(0).reset(new eth_socket(host, port, delimiter, timeout, 1));

这样就能保证旧对象先析构,新对象再构造。


内容的提问来源于stack exchange,提问作者xinthose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:27:50