是否可能在复制shared_ptr前,原shared_ptr已超出作用域?
这段代码片段是否有可能输出“Shared Ptr out of scope”?我想验证的是:在复制shared_ptr之前,原shared_ptr是否会先超出作用域。我知道shared_ptr拥有原子引用计数,但如果Test的拷贝构造函数在shared_ptr复制前被调用,同时主线程中的shared_ptr sp超出作用域,会发生什么?我尝试调整foo函数的参数顺序,结果一致,即代码块执行时会打印“Shared Ptr has value 9”。
struct Test { Test() = default; Test(const Test& t) { using namespace std::chrono_literals; for (int i = 0; i < 5; ++i) { std::cerr << "I am sleeping----\n"; std::this_thread::sleep_for(2000ms); } } }; void foo(std::shared_ptr<int> sp, Test t) { if (sp) std::cerr << "Shared Ptr has value "<<*sp; else std::cerr << "Shared Ptr out of scope"; } int main() { std::thread t; { Test tst; auto sp = std::make_shared<int>(9); t = std::move(std::thread(foo,sp, tst)); } if(t.joinable()) t.join(); }
回答
不会输出“Shared Ptr out of scope”,原因如下:
- 创建
std::thread对象时,所有传入的参数都会在主线程的当前作用域内完成拷贝,之后才会启动新线程执行目标函数。也就是说,不管参数顺序如何,shared_ptr<int>的复制(会原子性增加引用计数)和Test对象的拷贝构造,都是在主线程的代码块里完成的,此时原sp还未超出作用域。 - 即便Test的拷贝构造函数耗时很长,整个拷贝过程依然在主线程中执行,直到所有参数拷贝完成、
std::thread构造结束后,原作用域的sp和tst才会被销毁。此时shared_ptr的引用计数至少为2(原sp和传给线程的拷贝),原sp销毁后引用计数减为1,传给线程的拷贝依然有效,所以foo中的sp必然是有效的,会输出“Shared Ptr has value 9”。 - 调整参数顺序不会改变结果,因为所有参数的拷贝操作都发生在新线程启动前、主线程的作用域内,不存在“拷贝Test时原sp先销毁”的场景。
内容的提问来源于stack exchange,提问作者Rakesh Mehta
相关产品推荐
相关产品推荐

