【Example】C++ 标准库智能指针 unique_ptr 与 shared_ptr

【概念直接搬运Docs】C 样式编程的一个主要 bug 类型是内存泄漏。 泄漏通常是由于为分配的内存的调用失败引起的 delete new 。 现代 C++ 强调”资源获取即初始化”(RAII) 原则。 其理念很简单。 资源(堆内存、文件句柄、套接字等)应由对象”拥有”。 该对象在其构造函数中创建或接收新分配的资源,并在其析构函数中将此资源删除。 RAII 原则可确保当所属对象超出范围时,所有资源都能正确返回到操作系统。

为了支持对 RAII 原则的简单采用,C++ 标准库提供了三种智能指针类型:std::unique_ptrstd::shared_ptrstd::weak_ptr。 智能指针可处理对其拥有的内存的分配和删除。 下面的示例演示了一个类,其中包含一个数组成员,该成员是在调用 make_unique() 时在堆上分配的。 对和的 new 调用 deleteunique_ptr 类封装。 当 widget 对象超出范围时,将调用 unique_ptr 析构函数,此函数将释放为数组分配的内存。

在现代 c + + 编程中,标准库包含智能指针,这些指针用于帮助确保程序不会出现内存和资源泄漏,并具有异常安全。

====================================

unique_ptr

unique_ptr 类型智能指针在设计上最显著的特点是内部托管的指针一旦被创建就不能被任何形式的复制给另一个unique_ptr,只可以被移动给另一个unique_ptr。unique_ptr 没有拷贝构造函数,因此不能用于赋值。该指针最常用的情况是单例模式和编译防火墙的封装。当一个 std::unique 生命周期结束时,将释放所托管的内存,也就意味着,如果它作为一个局部变量托管一个对象,对象的生命周期也仅限于当前作用域范围,调用 reset() 或 operator= 时也会释放原有内存。

成员函数表:

名称 作用 operator= 赋值,如果已经存在托管的内存,会释放掉原有内存。 operator[] 数组下标形式访问。 release 返回一个指向被管理对象的裸指针,并释放所有权。 reset 释放原有对象内存,如果传递了参数,则替换为新指定的指针。 swap 交换两个 std::unique_ptr 对象 get 返回所托管对象的裸指针。

返回所托管对象的析构删除器。

检查是否有关联的被管理对象。

解引用。

解引用。

额外注解:

只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const std ::unique_ptr 所管理,则它被限定在创建指针的作用域中。 std::unique_ptr 常用于管理对象的生存期,包含:

  • 通过正常退出和经由异常退出两者上的受保证删除,提供异常安全,给处理拥有动态生存期的对象的类和函数

  • 传递独占的拥有动态生存期的对象的所有权到函数

  • 从函数获得独占的拥有动态生存期对象的所有权

  • 作为具移动容器的元素类型,例如保有指向动态分配对象的指针的std::vector (例如,若想要多态行为)
    std::unique_ptr 可为不完整类型 T 构造,例如用于改善用作 pImpl 手法中柄的用途。若使用默认删除器,则 T 必须在代码中调用删除器点处完整,这发生于析构函数、移动赋值运算符和 std::unique_ptrreset 成员函数中。(相反地, std::shared_ptr 不能从指向不完整类型的裸指针构造,但可于 T 不完整处销毁)。注意若 T 是类模板特化,则以 unique_ptr 为运算数的使用,如 !p ,因 ADL 而要求 T 的形参完整。
    T 是某基类 B 的导出类,则 std ::unique_ptr
    不同于 std::shared_ptr , std::unique_ptr 可通过任何满足可空指针 (NullablePointer) 的定制柄类型管理对象。例如,这允许管理位于共享内存,但提供定义 typedef boost::offset_ptr pointer; 或其他缀饰指针的 Deleter 的对象。

与 shared_ptr 搭配的 weak_ptr

weak_ptr 设计上与 shared_ptr 搭配使用, 因为 shared_ptr 存在一个问题,就是循环引用计数递增而导致的内存泄漏

比如说:

这种情况,两个node对象互相引用着对方,最终导致资源无法被释放。所以有时候需要访问 shared_ptr 自身,而不是它所托管的资源。

所以 weak_ptr 的作用就来了:

为什么呢?

因为 share_ptr 是强引用,强引用是只要被引用的对象还存活那么这个引用也一定会存在。

而 weak_ptr 是弱引用,弱引用是虽然对象还活着,但是这个引用则可有可无。

所以,weak_ptr 的作用就是作为一个 “观察者” 访问 shared_ptr 本身,而不是 shared_ptr 所托管的资源。

同时也意味着,weak_ptr 只能访问它所观察的shared_ptr 本身,而不能访问 share_ptr 托管的资源, 所以,它不会增加 shared_ptr 的引用计数

成员函数表:

名称 作用 operator= 赋值 reset 释放被管理对象的所有权 swap 交换被管理对象 use_count 返回当前所管理的对象引用计数。

检查被引用的对象是否已删除 lock 创建管理被引用的对象的

提供基于拥有者大小顺序的比较

额外补充:

std::bad_weak_ptr 是 std::shared_ptr 以 std::weak_ptr 为参数的构造函数,在 std::weak_ptr 指代已被删除的对象时,作为异常抛出的对象类型。

#include 
#include 
int main()
{
    std::shared_ptr<int> p1(new int(42));
    std::weak_ptr<int> wp(p1);
    p1.reset();
    try {
        std::shared_ptr<int> p2(wp);
    } catch(const std::bad_weak_ptr& e) {
        std::cout << e.what() << '\n';
    }
}

Original: https://www.cnblogs.com/airchip/p/15890186.html
Author: 芯片烤电池
Title: 【Example】C++ 标准库智能指针 unique_ptr 与 shared_ptr

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606302/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Monte Carlo 机器人定位——基于直方图过滤器的机器人定位方法

    本文为学习课程:https://classroom.udacity.com/courses/cs373 后的相关阶段总结,供个人学习也供大家参考。如有表述不当之处欢迎评论区指出。 …

    Linux 2023年6月14日
    0134
  • 一文搞懂 Redis 架构演化之路

    作者:ryetan,腾讯 CSIG 后台开发工程师 现如今 Redis 变得越来越流行,几乎在很多项目中都要被用到,不知道你在使用 Redis 时,有没有思考过,Redis 到底是…

    Linux 2023年5月28日
    0102
  • Ubuntu系统中MySQL安装后基本配置

    mysql8.0安装好后并不会让你输入root密码,而是采用默认账户+默认密码的方式保护数据库安全,但开发环境并不需要这样做。那么怎么找到这个默认账户和密码,又如何修改数据库使它可…

    Linux 2023年6月14日
    082
  • 中土批量运维神器《ps1屠龙刀》 pk 西域批量运维圣器《ansible圣火令》

    据故老相传,运维界有句话:”脚林至尊,宝刀【ps1屠龙】,号令被控,莫敢不从”。 https://gitee.com/chuanjiao10/kasini3…

    Linux 2023年5月27日
    0113
  • 如何分析redis中的慢查询

    慢查询只记录命令执行时间,并不包括命令排队和网络传输时间。因此客户端执行命令的时间会大于命令实际执行时间。因为命令执行排队机制,慢查询会导致其他命令级联阻塞,因此当客户端出现请求超…

    Linux 2023年5月28日
    090
  • centos7自动化ssh免密

    在做免密前要先手动生成公钥: ssh-keygen -t rsa 敲击三次回车即可 写一个shell脚本: expect命令可以获取到命令返回结果并且根据指定内容进行自动发送相应字…

    Linux 2023年6月6日
    0144
  • 容器编排与Kubernates

    1 基本概念 1.1 K8S优势 容器调度、容器管理、容器编排、容器集群管理工具。Google开源,自动化部署。支持弹性收缩、负载均衡。 1.2 K8S在Devops中的角色 ; …

    Linux 2023年6月13日
    0106
  • 《Redis开发与运维》——(八)理解内存(脑图)

    posted @2021-01-09 15:08 雪山上的蒲公英 阅读(122 ) 评论() 编辑 / 返回顶部代码 / Original: https://www.cnblogs…

    Linux 2023年5月28日
    0105
  • Jenkinsfile Pipeline 使用 SSH 连接

    为了在 Jenkinsfile 的命令中使用 SSH,我们不得不通过一些设置… 前提 首先你需要将用到的 SSH 私钥保存到 Jenkins 的凭据中,这样你会获得一个…

    Linux 2023年6月7日
    0116
  • Log4j 日志框架

    Log4j(Log for java)是 Apache 的一个开源项目,通过使用 Log4j,可以控制日志信息输送的目的地是控制台或文件等,也可以控制每一条日志的输出格式。通过定义…

    Linux 2023年6月8日
    0133
  • git使用命令行保留原分支迁移代码仓库

    有些时候我们需要对git仓库中的项目进行一些迁移,如从a账号迁移到b账号下,从github平台迁移到内部的gitlab平台等。一般平台会自带 migrate 或者 import 的…

    Linux 2023年6月7日
    0104
  • DNS Rebinding漏洞原理

    DNS Rebinding 广泛用于 绕过同源策略、SSRF过滤等。 背景 为什么需要SSRF过滤器?• 由于一些业务的需要,他们就是需要让用户输入URL,然后进行跳转,如果过滤得…

    Linux 2023年6月6日
    0121
  • CH343芯片应用—硬件设计

    CH343属于沁恒第三代USB转串口芯片系列的单串口型号,基于经典版CH340芯片完成技术革新,实现USB转高速异步串口,支持最高6Mbps串口波特率。 电源设计 CH343芯片有…

    Linux 2023年6月7日
    0166
  • 调度器简介

    内核中用来安排进程执行的模块称为调度器(scheduler),它可以切换进程状态(process state)。例如执行、可中断睡眠、不可中断睡眠、退出、暂停等。 调度器是CPU中…

    Linux 2023年6月7日
    077
  • MySQL — 数据操作语言

    DML 全称 Data Manipulation Language。数据操作语言,用来对数据库表中的数据进行增删改。 插入一条数据 插入多条数据 update &#x886…

    Linux 2023年6月8日
    0106
  • [20220314]利用vim下使用gdb进行各种进制转换插件.txt

    [20220314]利用vim下使用gdb进行各种进制转换插件.txt –//前一段时间学习使用gdb进行各种进制转换,当时遇到有时候16进制与10进制一起运算的问题,…

    Linux 2023年5月27日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球