智能指针(三) weak_ptr

weak_ptr本身也是一个模板类,但是不能直接用它来定义一个智能指针的对象,只能配合shared_ptr来使用,可以将shared_ptr的对象赋值给weak_ptr,并且这样并不会改变引用计数的值。查看weak_ptr的代码时发现,它主要有lockswapresetexpiredoperator=use_count几个函数,与shared_ptr相比多了lockexpired函数,但是却少了get函数,甚至连operator*operator->都没有

weak_ptr解决循环引用

weak_ptr必须跟shared_ptr配合使用, 它用于解决shared_ptr的死锁问题,如果两个shared_ptr一直互相引用,那么它们的引用计数永远不是0,资源永远不释放,这样实际造成了内存泄露。weak_ptr并不拥有其指向的对象,让weak_ptr指向shared_ptr所指向对象,对象的引用计数并不会增加

循环引用的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Son;
class Father
{
public:
~Father() {cout<<" father 析构"<<endl; }
shared_ptr<Son> son_;
};
class Son {
public:
~Son() {cout<<" son 析构"<<endl; }
shared_ptr<Father> father_;
};

auto father = make_shared<Father>();
auto son = make_shared<Son>();
father->son_ = son;
son->father_ = father;

结果一个析构函数也没运行,说明对象资源没有释放。使用weak_ptr解决很简单,让Son的成员变量father改为weak_ptr类型,运行后发现两个析构都有了。

main函数退出前,Son对象的引用计数是2,而Father的引用计数是1。
son指针销毁,Son对象的引用计数变成1。
father指针销毁,Father对象的引用计数变成0,导致Father对象析构,Father对象的析构会导致它包含的son_指针被销毁,这时Son对象的引用计数变成0,所以Son对象也会被析构。

参考:shared_ptr循环引用的例子及解决方法示例