当与std :: shared_ptr一起使用时,std :: atomic load方法会减少引用计数

Ric*_*erd 6 c++ atomic shared-ptr c++11

我想std::atomic<std::shared_ptr>在我的代码中使用a ,以便shared_ptr可以原子地更新,但是在访问shared_ptr时我遇到了问题.原子上的load()方法似乎减少了shared_ptr上的ref-count,因此我不能在不释放它的情况下实际使用该对象.

这是一段显示问题的简化代码......

typedef shared_ptr<MyClass> MyClassPtr;
typedef atomic<MyClassPtr> MyClassAtomicPtr;

// 1.
MyClassPtr ptr( new MyClass() );
printf("1. use_count=%d\n", ptr.use_count());

// 2. 
MyClassAtomicPtr atomicPointer(ptr);
printf("2. use_count=%d\n", ptr.use_count());

// 3.
{
    MyClassPtr p = atomicPointer.load();
    printf("3a. use_count=%d\n", ptr.use_count());
}
printf("3b. use_count=%d\n", ptr.use_count());

// 4.
{
    MyClassPtr p = atomicPointer.load();
    printf("4a. use_count=%d\n", ptr.use_count());
}
printf("4b. use_count=%d\n", ptr.use_count());
Run Code Online (Sandbox Code Playgroud)

这个输出是:

1. use_count=1
2. use_count=2
3a. use_count=2
3b. use_count=1
4a. use_count=1
4b. use_count=-572662307
Run Code Online (Sandbox Code Playgroud)

我理解第1步和第2步.但是在第3步,我希望对shared_ptr的赋值可以将ref-count增加到3,然后当它超出ref-count范围时返回到2.事实上,当分配时它保持在2,然后当shared_ptr超出范围时减少到1.类似地,在步骤4中,ref-count变为零并且删除对象.

所以我的问题是:如何在不破坏原子的情况下访问和使用原子管理的shared_ptr?

(我正在使用Visual Studio 2012版本11.0.50727.1 RTMREL进行编译)

nos*_*sid 8

您不能将其std::shared_ptr<T>用作模板参数类型std::atomic<T>."模板参数T的类型应该是可以轻易复制的." (N3290中的§29.51)std::shared_ptr<T>不是轻易复制的.

显然,在您的示例std::memcpy(或类似的东西)中用于复制std::shared_ptr,之后调用析构函数.这就是递减引用计数的原因.在最后一步中,删除该对象.

解决方案是使用a std::mutex来保护你的std::shared_ptr.

  • 他们可能在那里; 他们肯定在我为Dinkumware写的代码中,这就是微软发布的库.试试看,看看; 不在MSDN中意味着他们不在MSDN中. (2认同)

ken*_*ytm 5

我相信原子加载和存储共享指针的标准方法是使用§20.7.2.5[util.smartptr.shared.atomic]中的函数.似乎只有clac的libc ++支持它们:

template<class T> bool atomic_is_lock_free(const shared_ptr<T>* p);
template<class T> shared_ptr<T> atomic_load(const shared_ptr<T>* p);
template<class T> shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);
template<class T> void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);
template<class T> void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
template<class T> shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);
template<class T> shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
template<class T> bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
template<class T> bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
template<class T> bool atomic_compare_exchange_weak_explicit(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure);
template<class T> bool atomic_compare_exchange_strong_explicit(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure);
Run Code Online (Sandbox Code Playgroud)

所以你的代码可以写成:

auto ptr = std::make_shared<MyClass>();
printf("1. use_count=%d\n", ptr.use_count());

{
    auto p = std::atomic_load(&ptr);
    printf("3a. use_count=%d\n", ptr.use_count());
}

printf("3b. use_count=%d\n", ptr.use_count());

{
    auto p = std::atomic_load(&ptr);
    printf("3a. use_count=%d\n", ptr.use_count());
}

printf("4b. use_count=%d\n", ptr.use_count());
Run Code Online (Sandbox Code Playgroud)

但是我无法在MSDN上找到这样的支持,所以你能做的最好就是使用互斥锁.(实际上,libc ++中这些函数的实现也使用了互斥锁.)