weak_ptr如何知道共享资源已过期?

时间:2012-12-26 16:23:57

标签: c++ shared-ptr smart-pointers weak-ptr refcounting

考虑以下代码:

#include <memory>
#include <iostream>

using namespace std;

struct MySharedStruct
{
  int i;
};

void print_value_of_i(weak_ptr<MySharedStruct> weakPtr)
{
  if (shared_ptr<MySharedStruct> sp = weakPtr.lock())
  { cout << "Value of i = " << sp->i << endl; }
  else
  { cout << "Resource has expired"; }
}

int main()
{
  shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct() );
  sharedPtr->i = 5;

  weak_ptr<MySharedStruct> weakPtr;
  weakPtr = sharedPtr;

  print_value_of_i(weakPtr);

  sharedPtr.reset(new MySharedStruct() ); // <<----- How does weak_ptr know it has expired after this line executes?
  sharedPtr->i = 10;

  print_value_of_i(weakPtr);

  return 0;
}

考虑到weak_ptr引用的资源基本上已被其他资源取代,shared_ptr如何知道它已过期? weak_ptr跟踪知道共享资源是否被共享资源取代? lockweak_ptr方法的示例定义(如果相关)将不胜感激。

2 个答案:

答案 0 :(得分:10)

从普通指针创建shared_ptr时分配的控制块包含对象的引用计数器和指向对象本身的指针以及自定义删除对象(如果有)。当该引用计数器达到零时,释放该对象并将指针设置为null。因此,当对象引用计数器为零时,表示该对象已消失。

对于x86和x86-64,它们使用原子操作而没有显式锁定(没有互斥锁或自旋锁)。实现的技巧是一种特殊的无锁(繁忙旋转的代码语言)函数atomic_conditional_increment,只有在它不为零时才增加对象引用计数器。当多个线程尝试从对象引用计数器为零的同一weak_ptr::lock创建shared_ptr时,它用于执行weak_ptr函数以处理竞争。见http://www.boost.org/doc/libs/1_52_0/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp

控制块本身在shared_ptrweak_ptr之间共享,并且有自己的另一个引用计数器,因此它一直保持活动直到最后一次引用它为止被释放。

当重新分配shared_ptr时,它指向另一个控制块,因此控制块只指向一个相同的对象。换句话说,在控制块中没有一个对象替换另一个对象。

答案 1 :(得分:9)

简短回答

我怀疑大多数实现都是通过拥有weakPtrsharedPtr引用的共享控制块来实现的。重置sharedPtr时,它会减少控制块中的use_countweakPtr可用于测试指针是否有效。

答案很长

但我认为这可能因实施而异。以下是C ++ 11标准所说的应该发生的一瞥:

shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct());

Per 20.7.2.2.1 sharedPtr由给定数据的所有权构成。

weak_ptr<MySharedStruct> weakPtr;
weakPtr = sharedPtr;

20.7.2.3.1 ,构造weakPtr,然后赋值sharedPtr。分配后,weakPtrsharedPtr现在共享给定数据的所有权。

sharedPtr.reset(new MySharedStruct());

20.7.2.2.4 reset(Y*)相当于shared_ptr(Y*).swap(*this)。换句话说,sharedPtr使用拥有新数据的临时shared_ptr交换其内容。

交换后,sharedPtr将拥有新数据,临时将与weakPtr分享旧数据的所有权。

20.7.2.2.2 ,然后破坏临时性:

  • 由于临时拥有旧数据且未与其他shared_ptr实例共享该所有权,因此会删除旧数据。
  • 与临时shared_ptr共享所有权的所有实例都会报告比之前值少一个的use_count()

这意味着weakPtr.use_count() == 0

if (shared_ptr<MySharedStruct> sp = weakPtr.lock()) { 
  cout << "Value of i = " << sp->i << endl;
} else {
  cout << "Resource has expired"; 
}

20.7.2.3.5 ,调用lock等同于

expired() ? shared_ptr<T>() : shared_ptr<T>(*this)

......而expired()相当于

use_count() == 0

...这意味着lock将返回空的shared_ptr