前言,接上节:
为了解决循环引用,C++
提供了另外一种智能指针:weak_ptr
Weak_Ptr
weak_ptr
拥有共享语义(sharing semantics
)和不包含语义(not owning semantics
)。这意味着,weak_ptr
可以共享shared_ptr
持有的资源。所以可以从一个包含资源的shared_ptr
创建weak_ptr
。
weak_ptr
不支持普通指针包含的*
,->
操作。它并不包含资源所以也不允许程序员操作资源。既然如此,我们如何使用weak_ptr
呢?
答案是从weak_ptr
中创建shared_ptr
然后再使用它。通过增加强引用计数,当使用时可以确保资源不会被销毁。当引用计数增加时,可以肯定的是从weak_ptr
中创建的shared_ptr
引用计数至少为1
.否则,当你使用weak_ptr
就可能发生如下问题:当shared_ptr
离开作用域时,其拥有的资源会释放,从而导致了混乱。
创建
可以以shared_ptr
作为参数构造weak_ptr
.从shared_ptr
创建一个weak_ptr
增加了共享指针的弱引用计数(weak reference
),意味着shared_ptr
与其它的指针共享着它所拥有的资源。但是当shared_ptr
离开作用域时,这个计数不作为是否释放资源的依据。换句话说,就是除非强引用计数变为0
,才会释放掉指针指向的资源,在这里,弱引用计数(weak reference
)不起作用。
void main( )
{
shared_ptr<Test> sptr( new Test );
weak_ptr<Test> wptr( sptr );
weak_ptr<Test> wptr1 = wptr;
}
可以从下图观察shared_ptr
和weak_ptr
的引用计数:
将一个weak_ptr
赋给另一个weak_ptr
会增加弱引用计数(weak reference count
)。
所以,当shared_ptr
离开作用域时,其内的资源释放了,这时候指向该shared_ptr
的weak_ptr
发生了什么?weak_ptr
过期了(expired
)。
如何判断weak_ptr
是否指向有效资源,有两种方法:
- 调用
use-count()
去获取引用计数,该方法只返回强引用计数,并不返回弱引用计数。 - 调用
expired()
方法。比调用use_count()
方法速度更快。
从weak_ptr
调用lock()
可以得到shared_ptr
或者直接将weak_ptr
转型为shared_ptr
void main( )
{
shared_ptr<Test> sptr( new Test );
weak_ptr<Test> wptr( sptr );
shared_ptr<Test> sptr2 = wptr.lock( ); //增加强引用计数
}
如之前所述,从weak_ptr
中获取shared_ptr
增加强引用计数。
现在让我们见识一下weak_ptr
如何解决循环引用问题:
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
using namespace std;
#include <iostream>
#include <memory>
class B;
class A
{
public:
A() : m_a(5) { };
~A()
{
cout << " A is destroyed" << endl;
}
void PrintSpB();
weak_ptr<B> m_sptrB;
int m_a;
};
class B
{
public:
B() : m_b(10) { };
~B()
{
cout << " B is destroyed" << endl;
}
weak_ptr<A> m_sptrA;
int m_b;
};
void fun() {
shared_ptr<B> sptrB(new B);
shared_ptr<A> sptrA(new A);
sptrB->m_sptrA = sptrA;
sptrA->m_sptrB = sptrB;
}
int main()
{
fun();
getchar();
return 0;
}