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

Sam*_*rsa 11 c++ smart-pointers refcounting shared-ptr weak-ptr

考虑以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

weak_ptr考虑到shared_ptr引用的资源基本上被另一个资源取代,它是如何知道它已经过期的?什么是weak_ptr跟踪了解为确保共享资源被破坏和被替换新的共享资源?实施例定义(如果相关的话)的方法,例如lockweak_ptr将不胜感激.

Max*_*kin 10

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

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

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

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


Nat*_*ohl 9

简短的回答

我怀疑大多数实现都是通过拥有一个共享的控制块来实现这一点,weakPtr并且sharedPtr引用它们.当sharedPtr复位时,它会减少use_count控制块中的a ,weakPtr可用于测试指针是否有效.

答案很长

但我认为这取决于实施情况.以下是C++ 11标准所说的应该发生的事情:

shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct());
Run Code Online (Sandbox Code Playgroud)

根据给定数据,每20.7.2.2.1sharedPtr构造一次.

weak_ptr<MySharedStruct> weakPtr;
weakPtr = sharedPtr;
Run Code Online (Sandbox Code Playgroud)

20.7.2.3.1,weakPtr被构造和然后被分配的值sharedPtr.转让后,weakPtrsharedPtr现在分享给定数据的所有权.

sharedPtr.reset(new MySharedStruct());
Run Code Online (Sandbox Code Playgroud)

按照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()比其先前值小1的实例.

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

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

根据20.7.2.3.5,调用lock等同于

expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
Run Code Online (Sandbox Code Playgroud)

...... expired()等同于

use_count() == 0
Run Code Online (Sandbox Code Playgroud)

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