13

考虑以下代码:

#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_ptrlockweak_ptr

4

2 回答 2

14

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

对于 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_ptr控制块本身在's 和's之间共享,weak_ptr并且它自己有另一个引用计数器,因此它一直保持活动状态,直到释放对它的最后一个引用。

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

于 2012-12-26T16:30:53.577 回答
12

简短的回答

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

长答案

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

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

根据20.7.2.2.1sharedPtr构造具有给定数据的所有权。

weak_ptr<MySharedStruct> weakPtr;
weakPtr = sharedPtr;

根据20.7.2.3.1weakPtr构造并分配sharedPtr. 分配后,weakPtr现在sharedPtr共享给定数据的所有权。

sharedPtr.reset(new MySharedStruct());

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

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

根据20.7.2.2.2,临时对象随后被销毁:

  • 由于临时拥有旧数据并且不与另一个shared_ptr实例共享该所有权,因此它会删除旧数据。
  • 所有与临时共享所有权的实例都shared_ptr将报告use_count()比其先前值小一的 a。

这意味着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.

于 2012-12-26T17:58:31.207 回答