weak_ptr (到std:shared_ptr 所管理对象的弱引用)
正式介绍weak_ ptr 之前,先来回忆一下 shared_ptr 的一些知识。
- 我们知道shared_ptr 是采用引用计数的智能指针,多个shared_ptr
实例可以指向同一个动态对象,并维护了一个共享的引用计数器。 - 对于引用计数法实现的计数,总是避免不了循环引用(或环形引用)的问题,shared_ptr 也不例外。为了解决类似这样的问题,C++11 引入了weak ptr,来打破这种循环引用。
循环引用Demo
class Child;
class Parent
{
public:
shared_ ptr<Child> child;
~Parent() { cout << "Bye Parent" << endl; }
void hi() const { cout << "Hello" << endl; }
};
class Child
{
public:
shared_ ptr<Parent> parent ;
~Child() { cout << "Bye Child" << endl; }
};
int main()
{
shared_ ptr<Parent> parent = make_ shared<Parent>( );
shared_ ptr<Child> child = make_ shared<Child>() ;
parent->child = child;
child->parent = parent;
child->parent->hi();
return 0; .
}
输出为
Hello
weak_ ptr 是什么?
- weak_ptr是为了配合shared_ptr 而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是将一个weak_ptr绑定到一个shared_ ptr 不会改变shared_ptr的引用计数。
- 不论是否有weak _ptr指向,一旦最后一个指向对象的 shared_ptr被销毁,对象就会被释放。
- 从这个角度看,weak_ptr更像是shared_ptr 的一个助手而不是智能指针。
weak_ptr 如何使用?
1.如何创建weak_ ptr 实例
- 当我们创建一个 weak_ptr时,需要用一个shared_ptr实例来初始化weak _ptr, 由于是弱共享,weak_ptr的创建并不会影响shared_ptr的引用计数值。
int main()
{
shared_ ptr<int> sp(new int(5));
cout << "创建前sp的引用计数:”<< sp.use_ count() << end1l;
// use_count = 1
weak_ ptr<int> Wp(sp);
cout << "创建后sp的引用计数:”<< sp.use_ count() << endl;
// use_ count = 1
return 0;
}
2.如何判断weak_ptr 指向对象是否存在
- 既然weak_ptr 并不改变其所共享的shared_ ptr 实例的引用计数,那就可能存在weak_ptr指向的对象被释放掉这种情况。
- 这时,我们就不能使用weak _ptr 直接访问对象。那么我们如何判断weak_ptr 指向对象是否存在呢?
C+ +中提供了lock 函数来实现该功能。
- 如果对象存在,lock)函数返回一个指向共享对象的shared_ptr,
- 否则返回一个空shared_ptr.
如何使用weak_ptr
- weak_ ptr 并没有重载operator->和 operator *操作符,因此不可直接通过weak_ ptr
使用对象,典型的用法是调用其lock函数来获得shared_ptr 示例,进而访问原始对象。
最后,我们来看看如何使用weak_ptr 来改造最前面的代码,打破循环引用问题。
class Child;
class Parent
{
public:
weak_ ptr<Child> child;
~Parent() { cout << "Bye Parent" << endl; }
void hi() const { cout << "Hello" << endl; }
};
class Child
{
public:
weak_ ptr<Parent> parent; //
~Child() { cout << "Bye Child" << endl; }
};
int main()
{
shared_ ptr<Parent> parent = make_ shared<Parent>();
shared_ ptr<Child> child = make_ shared<Child>();
parent->child = child;
child->parent = parent;
//child->parent->hi(); //??
if(child-> expired())
{
child- >parent.1ock()->hi();
}
return 0;
输出为
Hello
Bye Child
Bye Parent
图论