【C++11新特性】 C++11智能指针之weak_ptr

来源:互联网 发布:js菜单滑动自动 编辑:程序博客网 时间:2024/06/05 18:10

原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/50772571

如题,我们今天要讲的是C++11引入的三种智能指针中的最后一个:weak_ptr。在学习weak_ptr之前最好对shared_ptr有所了解。如果你还不知道shared_ptr是何物,可以看看我的另一篇文章【C++11新特性】 C++11智能指针之shared_ptr。


1、为什么需要weak_ptr?

在正式介绍weak_ptr之前,我们先来回忆一下shared_ptr的一些知识。我们知道shared_ptr是采用引用计数的智能指针,多个shared_ptr实例可以指向同一个动态对象,并维护了一个共享的引用计数器。对于引用计数法实现的计数,总是避免不了循环引用(或环形引用)的问题,shared_ptr也不例外。

我们先来看看下面这个例子:

#include <iostream>#include <memory>#include <vector>using namespace std;class ClassB;class ClassA{public:    ClassA() { cout << "ClassA Constructor..." << endl; }    ~ClassA() { cout << "ClassA Destructor..." << endl; }    shared_ptr<ClassB> pb;  // 在A中引用B};class ClassB{public:    ClassB() { cout << "ClassB Constructor..." << endl; }    ~ClassB() { cout << "ClassB Destructor..." << endl; }    shared_ptr<ClassA> pa;  // 在B中引用A};int main() {    shared_ptr<ClassA> spa = make_shared<ClassA>();    shared_ptr<ClassB> spb = make_shared<ClassB>();    spa->pb = spb;    spb->pa = spa;    // 函数结束,思考一下:spa和spb会释放资源么?}

上面代码的输出如下:

ClassA Constructor...ClassB Constructor...Program ended with exit code: 0

从上面代码中,ClassA和ClassB间存在着循环引用,从运行结果中我们可以看到:当main函数运行结束后,spa和spb管理的动态资源并没有得到释放,产生了内存泄露。

为了解决类似这样的问题,C++11引入了weak_ptr,来打破这种循环引用。

2、weak_ptr是什么?

weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。不论是否有weak_ptr指向,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。从这个角度看,weak_ptr更像是shared_ptr的一个助手而不是智能指针。

3、weak_ptr如何使用?

接下来,我们来看看weak_ptr的简单用法。

3.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() << endl;    // use_count = 1    weak_ptr<int> wp(sp);    cout << "创建后sp的引用计数:" << sp.use_count() << endl;    // use_count = 1}

3.2如何判断weak_ptr指向对象是否存在

既然weak_ptr并不改变其所共享的shared_ptr实例的引用计数,那就可能存在weak_ptr指向的对象被释放掉这种情况。这时,我们就不能使用weak_ptr直接访问对象。那么我们如何判断weak_ptr指向对象是否存在呢?C++中提供了lock函数来实现该功能。如果对象存在,lock()函数返回一个指向共享对象的shared_ptr,否则返回一个空shared_ptr。

示例:

class A{public:    A() : a(3) { cout << "A Constructor..." << endl; }    ~A() { cout << "A Destructor..." << endl; }    int a;};int main() {    shared_ptr<A> sp(new A());    weak_ptr<A> wp(sp);    //sp.reset();    if (shared_ptr<A> pa = wp.lock())    {        cout << pa->a << endl;    }    else    {        cout << "wp指向对象为空" << endl;    }}

试试把sp.reset()这行的注释去掉看看结果有什么不同。

除此之外,weak_ptr还提供了expired()函数来判断所指对象是否已经被销毁。

示例:

class A{public:    A() : a(3) { cout << "A Constructor..." << endl; }    ~A() { cout << "A Destructor..." << endl; }    int a;};int main() {    shared_ptr<A> sp(new A());    weak_ptr<A> wp(sp);    sp.reset(); // 此时sp被销毁    cout << wp.expired() << endl;  // true表示已被销毁,否则为false}

代码输入如下:

A Constructor...A Destructor...1

3.3如何使用weak_ptr

weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。

最后,我们来看看如何使用weak_ptr来改造最前面的代码,打破循环引用问题。

class ClassB;class ClassA{public:    ClassA() { cout << "ClassA Constructor..." << endl; }    ~ClassA() { cout << "ClassA Destructor..." << endl; }    weak_ptr<ClassB> pb;  // 在A中引用B};class ClassB{public:    ClassB() { cout << "ClassB Constructor..." << endl; }    ~ClassB() { cout << "ClassB Destructor..." << endl; }    weak_ptr<ClassA> pa;  // 在B中引用A};int main() {    shared_ptr<ClassA> spa = make_shared<ClassA>();    shared_ptr<ClassB> spb = make_shared<ClassB>();    spa->pb = spb;    spb->pa = spa;    // 函数结束,思考一下:spa和spb会释放资源么?}

输出结果如下:

ClassA Constructor...ClassB Constructor...ClassA Destructor...ClassB Destructor...Program ended with exit code: 0

从运行结果可以看到spa和spb指向的对象都得到释放!

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子胳膊不小心烫破皮了怎么办 孩子嘴角磕破了怎么办 电话不小心拒接了怎么办 手机微信不小心碰到语言英文怎么办 手机微信不小心碰到英文说话怎么办 不小心碰到宝宝卤门怎么办 不小心碰到婴儿头顶囟门怎么办 重要部位被踢了怎么办 吃了带刺的葡萄怎么办 小孩子老是去厕所大便怎么办 家人偷了我的钱怎么办 小孩打闹踢到要害怎么办 腿上汗毛孔没开都是点点怎么办 脸蛋澡巾擦破了怎么办 婴儿后背用擦澡巾擦红了怎么办 搓澡皮肤搓破了怎么办 搓背搓的脖子红痒怎么办 上班迟到1个小时怎么办 想家想的都哭怎么办 想学手艺被骗学费怎么办 小腿肚后面筋和肌肉压痛怎么办 尿道囗和屁股眼中间长疮怎么办? 2个多月的宝宝蛋蛋上有个包怎么办 幼儿园睡觉自己摸下身玩怎么办 猫猫打喷嚏有透明液体怎么办 夏季穿运动鞋出了脚气怎么办 脚底长了刺瘊子怎么办 凉鞋前面踢破了怎么办 尖头鞋前面折了怎么办 月子里宝宝蛋蛋破皮怎么办 军人在训练时想上侧所怎么办 被白蚂蚁咬了怎么办 被蚂蚁咬了起包怎么办 脚踢了石头肿了怎么办 脚大拇指踢肿了怎么办 被骨头咯到了疼怎么办 被开水烫着了疼怎么办 鞋子上踩了口香糖怎么办 鞋底踩到口香糖干了怎么办 鞋子不小心踩到口香糖怎么办 站久了膝盖痛怎么办