16.3 C++智能指针-weak_ptr

16.1 C++智能指针-new/delete探秘
16.2 C++智能指针-shared_ptr
16.3 C++智能指针-weak_ptr
16.4 C++智能指针-shared_ptr使用场景、陷阱、性能分析与使用建议
16.5 C++智能指针-unique_ptr


    weak_ptr这个智能指针是用来辅助shared_ptr工作的。那么,现在就来介绍一下weak_ptr

3.weak_ptr

  3.1 weak_ptr简介

    weak_ptr是一个智能指针,也是一个类模板。这个智能指针指向一个由shared_ptr管理的对象,但是这种指针并不控制所指向的对象的生存期。换句话来说,将weak_ptr绑定到shared_ptr上并不会改变shared_ptr的引用计数(更确切地说,weak_ptr的构造和析构不会增加或者减少所指向对象的引用计数)。当shared_ptr需要释放所指向的对象时照常释放,不管是否有weak_ptr指向该对象。这就是weak“弱”的原因——能力弱(弱共享/弱引用:共享其他的shared_ptr所指向的对象),控制不了所指向对象的生存期
    创建weak_ptr的时候,一般是用一个make_shared来初始化
    前面谈到的shared_ptr指向的对象代表的引用统统指的都是强引用,而weak_ptr所指向的对象代表的引用统统都是弱引用
    weak_ptr所指向的对象有可能会不存在,所以,程序员是不能使用weak_ptr来直接访问对象的,必须要使用一个叫作lock的成员函数,lock的功能就是检查weak_ptr所指向的对象是否还存在,如果存在,lock能够返回一个指向共享对象的shared_ptr(当然原shared_ptr引用计数会+1),如果不存在,则返回一个空的shared_ptr。

{
    auto pi = make_shared<int>(100);
    weak_ptr<int> piw(pi); //piw弱共享pi,pi引用计数(强引用计数)不改变,弱引用计数字会从0变成1;pi和piw两者指向相同位置
    //weak_ptr<int> piw;
    piw = pi; //pi这里是一个shared_ptr,赋值给一个weak_ptr。pi和piw两者指向相同位置
    
    weak_ptr<int> piw2;
    piw2 = piw; //把weak_ptr赋给另外一个weak_ptr,现在pi是1个强引用,2个弱引用
    
    auto pi2 = piw.lock(); //强引用(shared_ptr)计数会加1,现在pi是2个强引用,2个弱引用
    if (pi2 != nullptr)    //条件成立;写成if(pi2)也可以
    {			
        cout << "所指对象存在" << endl;
    }		
}

在这里插入图片描述

{
    auto pi = make_shared<int>(100);
    weak_ptr<int> piw(pi); //piw弱共享pi,pi强引用计数不改变,弱引用计数字会从0变成1
    pi.reset();            //因为pi是唯一指向该对象的指针,则释放pi指向的对象,将pi置空
    
    auto pi2 = piw.lock(); //因为所指向的对象被释放了,所以piw弱引用也属于“过期”的了
    if (pi2 != nullptr)    //条件不再成立
    {
        cout << "所指对象存在" << endl;
    }
}

在这里插入图片描述

  3.2 weak_ptr常用操作

(1)use_count成员函数

    获取与该弱指针共享对象的其他shared_ptr的数量,或者说获得当前所观测资源的引用计数(强引用计数)

(2)expired成员函数

    是否过期的意思,若该指针的use_cout为0(表示该弱指针所指向的对象已经不存在),则返回true,否则返回false。换句话说,判断所观测的对象(资源)是否已经被释放。

{
    auto pi = make_shared<int>(100);
    auto pi2(pi); //pi2类型是个shared_ptr
    weak_ptr<int> piw(pi);
    int isc = piw.use_count(); //2:与本piw共享对象的shared_ptr数量
    pi.reset();
    pi2.reset();
    if (piw.expired()) //是否过期,此时成立
    {
        cout << "piw已过期" << endl;
    }		
}
{
    auto p1 = make_shared<int>(42);
    weak_ptr<int> pw;
    pw = p1;    //可以用shared_ptr给weak_ptr值,现在p1是1个强引用,1个弱引用
    if (!pw.expired()) //条件成立
    {
        //没过期:
        auto p2 = pw.lock(); //返回的p2是一个shared_ptr,现在p1是2个强引用,1个弱引用			
        if (p2 != nullptr)//条件成立
        {
            cout << "所指对象存在" << endl;
        }
        //离开这个范围,p1的强引用计数恢复为1,弱引用保持为1
    }
    else
    {
        cout << "pw已经过期" << endl;
    }
    //走到这里,p1是1个强引用,1个弱引用		
}
{
    weak_ptr<int> pw;
    {
        auto p1 = make_shared<int>(42);
        pw = p1; //可以用shared_ptr给weak_ptr值
    } //离开这里时p1就失效了,那么pw会变成啥情况?
    //这里pw这个weak_ptr就会过期了
    if (pw.expired()) //条件成立
    {
        cout << "pw已经过期" << endl;
    }		
}

在这里插入图片描述

(3)尺寸问题

    其实weak_ptr尺寸(就是大小或者sizeof)和shared_ptr对象尺寸一样大,后续章节里会提到shared_ptr的尺寸问题,这里先提一下weak_ptr对象尺寸问题。

{
    shared_ptr<int> p1(new int(100));
    weak_ptr<int> pw(p1);
    int ilen = sizeof(p1);  //8
    int ilen2 = sizeof(pw); //8
    cout << "设置断点" << endl;
}

在这里插入图片描述
在这里插入图片描述

    在当前Visual Studio的x86平台下,一个裸指针的sizeof值是4字节。从上面代码可以看到,weak_ptr或shared_ptr的尺寸都是8字节,其实,这8字节中包含了两个裸指针
可以看到:
(1)第一个裸指针指向的是该智能指针所指向的对象。
(2)第二个裸指针指向一个很大的数据结构(控制块)。这个控制块里面有:
    所指对象的引用计数。
    所指对象的弱引用计数。
    其他数据,如自定义的删除器的指针(如果指定了自定义删除器)等。
控制块实际是由shared_ptr创建出来的,而后,当使用shared_ptr对象创建weak_ptr对象时,weak_ptr对象也指向了这个控制块。具体后面还会讲到shared_ptr的控制块,到时再细讲。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值