C++11 检查共享ptr的唯一所有权

C++11 检查共享ptr的唯一所有权,c++11,thread-safety,smart-pointers,race-condition,C++11,Thread Safety,Smart Pointers,Race Condition,我经常想检查共享\u ptr是否是共享对象的唯一所有者。在销毁最后一个共享的\u ptr之前,可以方便地传递行为,而不必在销毁之后进行操作(我的特定用例是通过在销毁之前使用另一个shared\u ptr来保存弱指针。在销毁开始之后,要挽救它们已经太晚了) C++11[草案]20.7.2.1.4: 为了确定是否存在数据竞争,成员 功能应仅访问和修改共享ptr和弱ptr 对象本身,而不是它们所引用的对象。变化 use_count()不反映可能引入数据的修改 比赛 澄清了我对p的担忧。使用_count

我经常想检查
共享\u ptr
是否是共享对象的唯一所有者。在销毁最后一个共享的\u ptr之前,可以方便地传递行为,而不必在销毁之后进行操作(我的特定用例是通过在销毁之前使用另一个
shared\u ptr
来保存弱指针。在销毁开始之后,要挽救它们已经太晚了)

C++11[草案]20.7.2.1.4:

为了确定是否存在数据竞争,成员 功能应仅访问和修改共享ptr和弱ptr 对象本身,而不是它们所引用的对象。变化 use_count()不反映可能引入数据的修改 比赛

澄清了我对
p的担忧。使用_count()==1
导致数据竞争。然而,我仍然不相信以我想要的方式使用它是安全的

在单线程世界中,如果
use\u count()
返回1,则您知道您是该对象的最后所有者。在一个避免数据竞争的多线程世界中,
use\u count()
为1就足以确保您是唯一的所有者,这似乎是合理的,但我在试图从规范中获得这一点时遇到了挫折。我不知道是否存在允许使用计数为1的漏洞,即使另一个线程上存在另一个共享的ptr。另一方面,
use\u count
的定义可能会变为goo,这似乎令人沮丧,因为我将共享的ptr交给了另一个线程

如果
use\u count()
为1,但根据规范的规则,我不是唯一的所有者,我会遇到这种情况吗?我认识到,由于种族的原因,2的
use\u count
并不明确表示我在共享(在我调用
use\u count
这个线程后,另一个线程可能会释放我的对象),但一旦我看到1的
use\u count
,我就对另一个方向感兴趣了

作为第二个相关问题:相同的规则是否适用于
unique
,它似乎是根据我想要的实现定制的,但没有关于线程安全的任何额外声明



Edit:作为对我得到的答案的回应,我感兴趣的情况是我们调用的
unique\u count
只能由单个线程访问,因此我不必担心任何其他线程成功复制它。。。他们必须找到自己的
共享\u ptr
才能复制

当然。即使指定
use\u count()
unique()
都是原子的,但它不会:

long use_count()const noexcept
返回:与
*this
共享所有权的
共享\u ptr
对象(包括
*this
)的数量,或0 当
*此
为空时。
[注意:
use\u count()
不一定有效。-结束注意]

bool unique()const noexcept
返回:
use_count()==1

[注意:
unique()
写入时,当
get()==nullptr
-结束注释]

没有什么可以阻止这样的事情发生:

std::shared_ptr<Foo> sp;

// thread 1                      // thread 2    
bool uniq = sp.unique();    /**/
                            /**/   std::shared_ptr<Foo> cpy = sp;
if (uniq) {                 /**/
   /* mine?? */             /**/   cpy->foo();
   /* nope :-( */           /**/
}                           /**/
std::shared_ptr sp;
//线程1//线程2
bool uniq=sp.unique()/**/
/**/std::shared_ptr cpy=sp;
if(uniq){/**/
/*我的???*/**/cpy->foo();
/*否:-(*//**/
}                           /**/

如果存在指向与单个
共享\u ptr
相同控制块的
弱\u ptr
存在的可能性,并且如果另一个线程可能将该
弱\u ptr
转换为
共享\u ptr
,则您的线程可以观察到
使用\u count()==1,但当它可以利用该信息做任何事情时,另一个线程可以从
弱ptr
构造一个新的
共享ptr
,将
使用计数增加到2

即使没有
弱\u ptr
s,如果有多个线程具有对您的
共享\u ptr
的读取权限(例如,假设它是全局的),那么在您观察
use_count()==1
后,另一个线程可能会复制它


如果任何其他线程都无法访问您的
shared_ptr
,并且其他线程不可能将
弱_ptr
转换为
共享_ptr
,则
使用_count()==1
是可以安全依赖的。

请注意,您不需要另一个线程来复制将要发布的
共享ptr
,但另一个线程复制
共享ptr
或从
弱ptr
创建一个
共享ptr
就足够了,它与您要发布的
共享ptr
共享所有权即将发布。正如您所说,有
weak\u ptr
s存在,因此@Barry指出
use\u count
可能返回1是正确的,但在看到值后,另一个线程可能使用
weak\u ptr
创建了另一个引用。