考虑以下代码:
#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
跟踪知道旧共享资源是否被新共享资源取代? lock
中weak_ptr
方法的示例定义(如果相关)将不胜感激。
答案 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_ptr
和weak_ptr
之间共享,并且有自己的另一个引用计数器,因此它一直保持活动直到最后一次引用它为止被释放。
当重新分配shared_ptr
时,它指向另一个控制块,因此控制块只指向一个相同的对象。换句话说,在控制块中没有一个对象替换另一个对象。
答案 1 :(得分:9)
我怀疑大多数实现都是通过拥有weakPtr
和sharedPtr
引用的共享控制块来实现的。重置sharedPtr
时,它会减少控制块中的use_count
,weakPtr
可用于测试指针是否有效。
但我认为这可能因实施而异。以下是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
。分配后,weakPtr
和sharedPtr
现在共享给定数据的所有权。
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
。