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
相关产品推荐
相关产品推荐

