C++弱引用智能指针weak_ptr的用处

2023-11-18

weak_ptr也是一个引用计数型智能指针,但是它不增加对象的引用计数,即弱引用。与之相对,shared_ptr是强引用,只要有一个指向对象的shared_ptr存在,该对象就不会析构,直到指向对象的最后一个shared_ptr析构或reset()时才会被销毁。

利用weak_ptr,我们可以解决常见的空悬指针问题以及循环引用问题

空悬指针问题

什么是空悬指针?考虑以下这种情况:

这里写图片描述

有两个指针p1和p2,指向堆上的同一个对象Object,p1和p2位于不同的线程中。假设线程A通过p1指针将对象销毁了(尽管把p1置为了NULL),那p2就成了空悬指针。这是一种典型的C/C++内存错误。

使用weak_ptr能够帮我们轻松解决上述的空悬指针问题。

weak_ptr不控制对象的生命期,但是它知道对象是否还活着。如果对象还活着,那么它可以提升为有效的shared_ptr(提升操作通过lock()函数获取所管理对象的强引用指针);如果对象已经死了,提升会失败,返回一个空的shared_ptr。示例代码如下:

#include <iostream>
#include <memory>

int main()
{
    // OLD, problem with dangling pointer
    // PROBLEM: ref will point to undefined data!

    int* ptr = new int(10);
    int* ref = ptr;
    delete ptr;

    // NEW
    // SOLUTION: check expired() or lock() to determine if pointer is valid

    // empty definition
    std::shared_ptr<int> sptr;

    // takes ownership of pointer
    sptr.reset(new int);
    *sptr = 10;

    // get pointer to data without taking ownership
    std::weak_ptr<int> weak1 = sptr;

    // deletes managed object, acquires new pointer
    sptr.reset(new int);
    *sptr = 5;

    // get pointer to new data without taking ownership
    std::weak_ptr<int> weak2 = sptr;

    // weak1 is expired!
    if(auto tmp = weak1.lock())
        std::cout << *tmp << '\n';
    else
        std::cout << "weak1 is expired\n";

    // weak2 points to new data (5)
    if(auto tmp = weak2.lock())
        std::cout << *tmp << '\n';
    else
        std::cout << "weak2 is expired\n";
}

循环引用问题

一种循环引用的情况如下:

#include <iostream>
#include <memory>

using namespace std;

class Parent;
class Child; 

typedef shared_ptr<Parent> parent_ptr;
typedef shared_ptr<Child> child_ptr; 

class Parent
{
public:
       ~Parent() { 
              cout << "~Parent()" << endl; 
       }
public:
       child_ptr children;
};

class Child
{
public:
       ~Child() { 
              cout << "~Child()" << endl; 
       }
public:
       parent_ptr parent;
};

int main()
{
  parent_ptr father(new Parent);
  child_ptr son(new Child);

  // 父子互相引用
  father->children = son;
  son->parent = father;

  cout << father.use_count() << endl;  // 引用计数为2
  cout << son.use_count() << endl;     // 引用计数为2

  return 0;
}

如上代码,将在程序退出前,father的引用计数为2,son的计数也为2,退出时,shared_ptr所作操作就是简单的将计数减1,如果为0则释放,显然,这个情况下,引用计数不为0,于是造成father和son所指向的内存得不到释放,导致内存泄露。

使用weak_ptr可以打破这样的循环引用。由于弱引用不更改引用计数,类似普通指针,只要把循环引用的一方使用弱引用,即可解除循环引用。

这里写图片描述

以上述代码为例,只要把Child类的代码修改为如下即可:

class Child
{
public:
       ~Child() { 
              cout << "~Child()" << endl; 
       }
public:
       weak_ptr<Parent> parent; 
};

最后值得一提的是,虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在能预见会出现循环引用的情况下才能使用,即这个仅仅是一种编译期的解决方案,如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的。因此,不要认为只要使用了智能指针便能杜绝内存泄漏。


参考资料:
When is std::weak_ptr useful?
http://stackoverflow.com/questions/12030650/when-is-stdweak-ptr-useful

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++弱引用智能指针weak_ptr的用处 的相关文章

  • C++_生成随机字符串

    include
  • fastcgi的环境变量

    FCGI ROLE RESPONDER SCRIPT FILENAME scripts 5 cgi QUERY STRING aaa 11111111111111 bbb 2222222222222222 ccc 3333333333333
  • R语言学习笔记:分析学生的考试成绩

    孩子上初中时拿到过全年级一次考试所有科目的考试成绩表 正好可以用于R语言的统计分析学习 为了不泄漏孩子的姓名 就用学号代替了 感兴趣可以下载测试数据进行练习 num class chn math eng phy chem politics
  • C++中的namespace

    namespace中文意思是命名空间或者叫名字空间 传统的C 只有一个全局的namespace 但是由于现在的程序的规模越来越大 程序的分工越来越细 全局作用域变得越来越拥挤 每个人都可能使用相同的名字来实现不同的库 于是程序员在合并程序的
  • [原]Pro*C介绍-内嵌SQL

    Translate by Z Jingwei Document address http www db stanford edu ullman fcdb oracle or proc html Pro C介绍内嵌SQL 概要 Pro C语法
  • 五. python面向对象(多态 和metaclass=abc.ABCMeta)

    一 多态 多肽 一种事物的多种形态 叫多肽 例如 动物 animal 猫 狗 animal py 文件 动物类 都有名字这个属性 和吃这个方法 class Animal object def init self name self name
  • Qt5学习之路(vs2012下创建一个QT应用程序)2013-10-14

    刚开始学习QT在网上找的资料基本都是使用QT Create进行开发的 VS下开发的学习资料感觉很少很难找的到 视频教程也基本没看到过貌似 因为我们研发中心是使用MFC进行开发开发工具是VS2010 使用QT开发的话基本我们不会再使用QT C
  • 多线程系列之——事件内核对象

    所有内核对象里面事件内核对象是最简单的一个 它包括一个使用计数 还有两个布尔值 一个布尔值用来表示事件是手动重置事件还是自动重置事件 另一个布尔值表示当前是否处于触发状态 当一个手动重置事件被触发的时候 所有等待该事件的线程都能变成调度状态
  • 编写程序模拟完成动态分区存储管理方式的内存分配和回收。

    usr bin python coding utf 8 class Table object 空闲分区表 0 开始地址 1 长度 freeTable 占用分区表 0 程序名 1 开始地址 2 长度 useTable def init sel
  • c/c++入门教程 - 1.基础c/c++ - 1.0 Visual Studio 2019安装环境搭建

    推荐视频课程 https www bilibili com video BV1et411b73Z p 2 已投币三连 b站果然是个学习的网站 本来是想在linux环境下运行QT 于是先学了几个月linux嵌入式驱动开发 后来发现太底层了 与
  • 简析多级指针解引用

    转自 简析多级指针解引用 指针是C语言中公认的最为强大的语法要素 但同时也是最难理解的语法要素 它曾给程序员带来了无数麻烦和痛苦 以致于在C语言之后诞生的很多新兴 语言中我们再也难觅指针的身影了 下面是一个最简单的C语言指针的例子 int
  • C/C++中浮点数格式学习——以IEEE75432位单精度为例

    这是浮点数的通常表示形式 在IEEE754中 单精度浮点数有如下形式 32位单精度 单精度二进制小数 使用32个比特存储 1 8 23位长 S Exp Fraction 31 30至23偏正值 实际的指数大小 127 22至0位编号 从右边
  • 大端模式和小端模式转化

    在工作中遇到一个问题 数据是以大端模式存储的 而机器是小端模式 必须进行转换 否则使用时会出问题 一 定义 大端模式 Big Endian 数据的高字节 保存在内存的低地址中 数据的低字节 保存在内存的高地址中 小端模式 Little En
  • ATL字符串转换宏

    有比MultiByteToWideChar和WideCharToMultiByte更简单的字符串转换宏 你相信吗 头文件 d program files microsoft visual studio 8 vc atlmfc include
  • LeetCode题目笔记——17.19消失的两个数字

    文章目录 题目描述 题目难度 困难 方法一 暴力 代码 代码优化 方法二 数学方法 代码 总结 题目描述 题目直达 题目难度 困难 方法一 暴力 虽然题目说你能在 O N 时间内只用 O 1 的空间找到它们吗 但是也没有限制我们不能用暴力
  • Dev-C++之开启装逼效果

    Dev C 是个不错的C IDE 在10年前 它是很不错 在现在 它是个以界面丑陋和调试像吃粑粑这两点著称 如下图 实在是丑到离谱 丑到无法忍受 可是没办法呀 人家CCF规定比赛用这个 你个小蒟蒻吵什么 我现在就来讲讲怎么把你的Dev C
  • visual studio 一直显示正在准备解决方案

    首先重启电脑 无法解决的情况下执行以下步骤 Kill Visual Studio Open Visual Studio without loading a solution Disable AnkhSvn as Source Control
  • stat 函数解析

    stat 函数的简单使用 stat 函数是用来获取文件的各种属性的一个linux下的常用API函数 函数原型为int stat const char path struct stat buf stat定义如下 struct stat dev
  • C/C++编程:令人印象深刻的高级技巧案例

    C C 编程语言在软件开发领域有着悠久的历史 由于其高效 灵活和底层访问能力 至今仍然被广泛应用 本文将介绍一些在C C 编程中令人印象深刻的高级技巧 帮助读者提升编程水平 更加高效地使用这两种强大的编程语言 一 指针运算与内存管理 C C
  • C++ 中 const 和 constexpr 关键字解析:常量、函数和指针

    很多 C 的初学者看到 const 这个关键字的第一反应都是一头雾水 主要是因为 const 可 以出现在很多的位置 以及后面加入的 constexpr 更是常常感到困惑 今天就为大家一一解释出现它们的含义和以及作用 const 关键字 c

随机推荐

  • [Python]调用pytdx的代码示例

    安装pytdx pip install pytdx 简单示范 from pytdx hq import TdxHq API api TdxHq API 数据获取接口一般返回list结构 with api connect 119 147 21
  • vue常用面试题(三)

    1 计算属性computed是一个对象的时候 他有哪些选项 有get和set俩个选项 2 computed和methods有什么区别 计算属性具有缓存机制 methods中的方法每使用一次方法就会被调用一次 不管里面的数据是否发生变化 而使
  • 电机系统标幺值基准值的选取

    电机系统标幺化的好处 对于不同功率 电压值的设备标幺值在一定范围内 具有可比性 而测量值则随之变化 定点DSP控制 可有效防止数据溢出 各个基值的选取方式如下 转载于 https www cnblogs com derek32 p 3855
  • React入门小册(六) 状态提升与状态共享

    React 状态提升指的是将多个组件所共享的状态提升到它们的公共父组件中 以便于修改和同步这些数据的变化 一般而言 状态提升对于多个组件的功能需求相似 并且存在一定的层次结构时 是非常有用的 在实际应用开发中 我们经常会遇到需要将数据传递给
  • 问卷数据怎么处理、分析?

    调查问卷分析是一门很系统很成熟的科学 无论是基于何种目的的调查 学术 市场调研 产品调研 用户调研 还是哪种方式发放的问卷 纸质问卷 电子问卷 面对回收的庞杂的问卷 最重要的事情就是如何处理 得出我想想要的结论呢 1 准备工作 在发放问卷前
  • 常见汇编指令整理

    本文会整理在逆向中常见的指令汇总 目录 汇编符号 汇编指令的组成 mov movzx lea xchg 加法指令 减法指令 带进位加法 带进位减法 自增自减 乘法运算 除法运算 and or xor not shl shr 逻辑指令 字符串
  • Tesseract学习(四)

    本文将介绍如何在C 下调用Tesseract OCR 由于现在已经有编译好的dll文件 所以只需添加引用到项目中即可 dll文件可在此处下载 下载后添加到项目中 另外需要自己下载语言库 注意版本为3 01 此处为英文语言库 与在C 下添加引
  • 日常开发中,提升技术的13个建议

    最近有位好友问我 日常开发中 都是在做业务需求 如何提升自己的技术呢 因此 本文小黑整理了提升技术的13个建议 小伙伴们 一起加油 1 打好基础 深入学习语言特性 比如 对于Java程序员来说 要了解Java语言的基本概念和核心特性 包括面
  • 100天精通Python(基础篇)——第11天:面向对象基本概念

    作者介绍 Python领域优质创作者 数据开发工程师 励志成为Python全栈工程师 关注我发现更多精彩 本文已收录于Python全栈系列专栏 100天精通Python从入门到就业 欢迎订阅 订阅后可私聊进Python全栈VIP交流群 手把
  • 从理论到实践,让你全面看懂OKR!

    转自 http blog mingdao com 3934 html OKR资料全集已上线 你可以点击这里获取下载 文 明道 夏英凯 去年4月份 明道开了第一次OKR会议 那是我第一次接触OKR 当时就从心里喜欢上了这种管理方法 没想到后来
  • 电脑删除的文件如何找回?找回删除的文件有3个方法…

    大家的电脑存放着各种各样的文件 不能说每个文件都非常重要 但如果丢失了的话 电脑删除的文件如何找回 对于找回删除的文件这一块大家估计也花了不少心思 倒不是说一定要非要找回不可 电脑中的文件即便不是非常重要的 但是如果到了想要用的时候又得重新
  • 【log4j2】下载、安装、使用

    目录 1 下载 2 安装 3 使用 1 下载 https logging apache org log4j 2 x download html 下载文件名 apache log4j 2 14 1 bin zip 2 安装 1 解压 apac
  • 用VScode+anaconda搭建Python环境

    Python的IDE有很多 自带的IDLE spyder pycharm等都可以 但我目前用得最上手的是VScode 搭载anaconda 优点就是写代码效率高 第三方库导入一次性到位 下面介绍安装和配置教程 安装VS code 细节可以参
  • iPhone手机连接蓝牙鼠标和蓝牙键盘

    iPhone手机升级了IOS13之后 无意中发现了一个有趣的功能 iPhone手机可以连接蓝牙鼠标 具体方式如下 首先 要买一个支持蓝牙功能的鼠标 我用的罗技M590 建议再买一个蓝牙键盘 打开手机蓝牙 和蓝牙鼠标建立连接 这一步鼠标的说明
  • lVS+keepalived集群

    lvs keepalived 需要四台虚拟机 LVS 主 DIP 10 0 0 31 VIP 10 0 0 99 LVS 备 DIP 10 0 0 32 VIP 10 0 0 99 WEB1 RIP 10 0 0 33 VIP 10 0 0
  • 好看视频在线下载

    有时候在网上看到漂亮的小姐姐 想下载下来怎么办 比如这位漂亮的小姐姐 点击下面的示例地址就可以看到 https haokan baidu com videoui page videoland context 7B 22nid 22 3A 2
  • QOpenglWidget屏幕坐标系转到vtk世界坐标系

    原文 QOpenglWidget屏幕坐标系转到vtk世界坐标系 QOpenglWidget屏幕坐标系转到vtk世界坐标系 前两天看到有人问vtk的坐标系和qt的坐标系不同 之前有用qt实现了下vtk的测量距离和测量角度 其中就用到了QOpe
  • 使用MATLAB搭建深度神经网络(DNN)

    使用MATLAB搭建深度神经网络 DNN 深度神经网络 Deep Neural Network DNN 是一种强大的机器学习模型 常用于解决图像识别 自然语言处理 语音识别等任务 在本文中 我们将使用MATLAB搭建一个简单的DNN 并提供
  • 异常分类

    异常数据挖掘其中又包含 时间序列和非时间序列 非时间序列主要为发现异常的点集 其中各事件的发生无先后顺序 一般的探测手法为使用距离度量进行聚类 分类等操作 发现事件中的离群点 时间序列各点 各时间的发生需要考虑先后顺序 各点 各事件之间存在
  • C++弱引用智能指针weak_ptr的用处

    weak ptr也是一个引用计数型智能指针 但是它不增加对象的引用计数 即弱引用 与之相对 shared ptr是强引用 只要有一个指向对象的shared ptr存在 该对象就不会析构 直到指向对象的最后一个shared ptr析构或res