下面的代码片段运行正常:
#include <memory>
#include <cassert>
int main()
{
auto ptr1 = std::make_shared<int>(10);
assert(ptr1.use_count() == 1);
auto ptr2 = std::move(ptr1);
assert(ptr1 == nullptr);
auto ptr3 = static_cast<std::shared_ptr<int>&&>(ptr2);
assert(ptr2 == nullptr);
assert(ptr3.use_count() == 1);
}
看起来std::move
做了几个操作,其中一个是重置移动的共享指针,所以这个线程安全吗?例如,如果我有这样的内容:
void ThreadLogic()
{
if (sharedPtr != nullptr)
{
DoSomething(std::move(sharedPtr));
}
else
{
DoSomethingElse();
}
}
是std::move(sharedPtr)
原子还是我应该用其他方法保护检查(临界区)?
你对std::move
的作用有误解。事实上,std::move
对没有任何作用。它只是一个编译时机制,其含义是:我不再需要这个命名值.
这会导致编译器以不同的方式使用该值,比如调用移动构造函数/赋值函数,而不是调用复制构造函数/赋值函数。但是std::move
本身不生成代码,所以不会受到线程的影响。
你应该问的真正问题是shared_ptr
的move构造函数是否线程安全,答案是:否。
但是shared_ptr
的重点不是分享shared_ptr
,而是分享它所指向的东西。不要将shared_ptr
通过引用传递给线程,而是通过值传递,这样每个线程都可以获得自己的shared_ptr
。然后,它可以自由地移动,没有问题。
shared_ptr
保护它所指向的对象的生命周期。shared_ptr
使用的引用计数是线程安全的,仅此而已。它只以线程安全的方式管理被指向对象的生命周期,因此只要任何shared_ptr
持有该对象,它就不会被销毁。