C++标准库学习之weak_ptr智能指针用法详解

 更新时间:2023年12月06日 14:22:53   作者:tsm  
这篇文章主要为大家详细介绍了C++标准库中weak_ptr智能指针用法的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

在上一篇文章中介绍了 shared_ptr 这种智能指针,他为了解决在指针没有引用的情况下自动回收资源这种情况而产生的,但是在部分情况下会产生另一种问题,那就是两个智能指针被循环引用 , a 使用 shared_ptr 引用了b ,同时 b 使用 shared_ptr 引用了 a,在 方法执行完成后 ,a 与 b 的智能指针都会被 释放,但是 由于他们互相持有 , a 与 b 的 used_count >0 ,那么就不会释放他们的资源,看下面的例子

#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class Person{
public:
    // 构造方法 ,name 是必要参数  mum 与 dad 是非必要参数 
    Person(string name,shared_ptr<Person> mum = nullptr ,shared_ptr<Person> dad = nullptr)
    :name(name) ,mum(mum),dad(dad)// 此种初始化方式被经常应用到 jni 源码上
    {
    }
    // 析构函数,资源被释放时会被调用
    ~Person(){
        cout<<"对象名称是->" << name<< "被回收了"<<endl;
    }
    // 向量 
    vector<shared_ptr<Person>> child;
    //名字
    string name;
    // 智能指针引用mum
    shared_ptr<Person> mum;
    //智能指针引用dad
    shared_ptr<Person> dad;
};
// 初始化 家人,让他们循环引用
shared_ptr<Person> getFamily(const string& name){
    shared_ptr<Person> mum(new Person(name +"'s Mum"));
    shared_ptr<Person> dad(new Person(name +"'s Dad"));
    shared_ptr<Person> child(new Person(name,mum,dad));
    mum->child.push_back(child);
    dad->child.push_back(child);
    return child;
}
int main(){
    shared_ptr<Person> tsm=  getFamily("tsm");
    cout<< "------------before  change-----------"<<endl;
    cout << tsm->dad->name<<endl;
    cout << tsm->mum->name<<endl;
    cout << tsm->name<<endl;
    cout<<"tsm 的引用个数" <<tsm.use_count()<<endl;
    cout<< "------------start change-----------"<<endl;
    tsm = getFamily("tsm1");
    cout<< "------------after change-----------"<<endl;
    system("pause");
    return 0;
}

结果:

D:\CWorkSpace\tsmTest\cmake-build-debug\tsmTest.exe
------------before  change-----------
tsm's Dad
tsm's Mum
tsm
tsm 的引用个数3
------------start change-----------
------------after change-----------
. . . pause . . . 

发现在为 tsm 这个变量二次赋值时,第一次 shared_ptr 指针指向的资源内存应该是被释放的,但是他们的析构函数并没有被执行,那就证明他的资源并没有被释放,那么我们如何来修改内,这就引出了我们今天的主角 weak_ptr

修改如下

class Person{
public:
    // 构造方法 ,name 是必要参数  mum 与 dad 是非必要参数
    Person(string name,shared_ptr<Person> mum = nullptr ,shared_ptr<Person> dad = nullptr)
    :name(name) ,mum(mum),dad(dad)// 此种初始化方式被经常应用到 jni 源码上
    {
    }
    // 析构函数,资源被释放时会被调用
    ~Person(){
        cout<<"对象名称是->" << name<< "被回收了"<<endl;
    }
    // 将向量中的引用使用  weak_ptr ,打破互相引用即可
    vector<weak_ptr<Person>> child;
    //名字
    string name;
    // 智能指针引用mum
    shared_ptr<Person> mum;
    //智能指针引用dad
    shared_ptr<Person> dad;
};

修改后的结果如下:

------------before  change-----------
tsm's Dad
tsm's Mum
tsm
tsm 的引用个数1
------------start change-----------
对象名称是->tsm被回收了
对象名称是->tsm's Dad被回收了
对象名称是->tsm's Mum被回收了
------------after change-----------

发现在使用 weak_ptr 打破互相引用的后, 被覆盖的 tsm 的析构函数被成功调用了,

weak_ptr 的使用场景主要有2个

1: 打破 shared_ptr 使用混乱出现的情况导致循环引用的情况,

2: 如果持有该 shared_ptr 的对象的生命周期是大于 该 shared_ptr 指针的生命周期的情况,就会导致 shared_ptr 资源无法被回收,

weak_ptr 的创建方式有3中

1:

weak_ptr<Person> t0; //构造空对象

2:

weak_ptr<Person> t1(t0); //使用拷贝构造函数

3:

shared_ptr<Person> tsm=  getFamily("tsm");

weak_ptr<Person> t2(tsm);

检查weak_ptr 是否还有效

t2.expired() 

expired 源码如下

bool
expired() const noexcept
{ return _M_refcount._M_get_use_count() == 0; }

可以看到 返回的是 use_count ,那就证明 if(!t2.expired) 则证明他是有效的

使用 weak_ptr,使用lock 方法将 weak_ptr 转换成 shared_ptr ,防止在使用过程中资源被回收

shared_ptr<Person> tt =  t2.lock();

看一下lock 的源码

shared_ptr<_Tp>
lock() const noexcept
{ return shared_ptr<_Tp>(*this, std::nothrow); }

到此这篇关于C++标准库学习之weak_ptr智能指针用法详解的文章就介绍到这了,更多相关C++ weak_ptr智能指针内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ random_shuffle()方法案例详解

    C++ random_shuffle()方法案例详解

    这篇文章主要介绍了C++ random_shuffle()方法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • C++面试八股文之std::string实现方法

    C++面试八股文之std::string实现方法

    这篇文章主要介绍了C++面试八股文:std::string是如何实现的,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • 深入了解C++11中promise和future的使用

    深入了解C++11中promise和future的使用

    C++11中promise和future机制是用于并发编程的一种解决方案,用于在不同线程完成数据传递(异步操作)。Promise和Future提供了访问异步操作结果的机制,可以在线程之间传递数据和异常消息。本文就来聊聊二者的使用,希望对大家有所帮助
    2022-11-11
  • C语言实现无头单向链表的示例代码

    C语言实现无头单向链表的示例代码

    本文主要介绍了C语言实现无头单向链表的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • C语言多维数组数据结构的实现详解

    C语言多维数组数据结构的实现详解

    对于数组想必大家都不陌生首先得要知道的是对于数组元素在内存存储是连续性的,下面这篇文章主要给大家介绍了关于C语言多维数组数据结构的相关资料,需要的朋友可以参考下
    2021-12-12
  • C++ 流插入和流提取运算符的重载的实现

    C++ 流插入和流提取运算符的重载的实现

    这篇文章主要介绍了C++ 流插入和流提取运算符的重载的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • C语言数据结构之图的遍历实例详解

    C语言数据结构之图的遍历实例详解

    这篇文章主要介绍了C语言数据结构之图的遍历实例详解的相关资料,需要的朋友可以参考下
    2017-07-07
  • Seesion在C++服务端的使用方法

    Seesion在C++服务端的使用方法

    这篇文章主要介绍了Seesion在C++服务端是怎么使用的?本文给出了解决方案和实例代码供大家参考,需要的朋友可以参考下
    2020-02-02
  • C++交换指针实例

    C++交换指针实例

    这篇文章主要介绍了C++交换指针实例,针对C与C++交换指针的方法进行了较为详细的对比分析,非常具有实用价值,需要的朋友可以参考下
    2014-10-10
  • C++基于递归算法解决汉诺塔问题与树的遍历功能示例

    C++基于递归算法解决汉诺塔问题与树的遍历功能示例

    这篇文章主要介绍了C++基于递归算法解决汉诺塔问题与树的遍历功能,简单描述了递归算法的原理,并结合实例形式分析了基于递归算法解决汉诺塔问题与数的遍历相关操作技巧,需要的朋友可以参考下
    2017-11-11

最新评论