C++11新特性——智能指针之shared_ptr

2023-11-16

此课件及源代码来自B站up主:码农论坛,该文章仅作为本人学习笔记使用。

1、智能指针shared_ptr

shared_ptr共享它指向的对象,多个shared_ptr可以指向(关联)相同的对象,在内部采用计数机制来实现。

当新的shared_ptr与对象关联时,引用计数增加1。

shared_ptr超出作用域时,引用计数减1。当引用计数变为0时,则表示没有任何shared_ptr与对象关联,则释放该对象。

一、基本用法

shared_ptr的构造函数也是explicit,但是,没有删除拷贝构造函数和赋值函数。

1)初始化

方法一:

shared_ptr<AA> p0(new AA("zq"));     // 分配内存并初始化。

方法二:

shared_ptr<AA> p0 = make_shared<AA>("zq");  // C++11标准,效率更高。

shared_ptr<int> pp1=make_shared<int>();         // 数据类型为int。

shared_ptr<AA> pp2 = make_shared<AA>();       // 数据类型为AA,默认构造函数。

shared_ptr<AA> pp3 = make_shared<AA>("zq");  // 数据类型为AA,一个参数的构造函数。

shared_ptr<AA> pp4 = make_shared<AA>("zq",8); // 数据类型为AA,两个参数的构造函数。

方法三:

AA* p = new AA("zq");

shared_ptr<AA> p0(p);                  // 用已存在的地址初始化。

方法四:

shared_ptr<AA> p0(new AA("zq"));

shared_ptr<AA> p1(p0);                 // 用已存在的shared_ptr初始化,计数加1。

shared_ptr<AA> p1=p0;                 // 用已存在的shared_ptr初始化,计数加1。

2)使用方法

  1. 智能指针重载了*和->操作符,可以像使用指针一样使用shared_ptr
  2. use_count()方法返回引用计数器的值。
  3. unique()方法,如果use_count()为1,返回true,否则返回false
  4. shared_ptr支持赋值,左值的shared_ptr的计数器将减1,右值shared_ptr的计算器将加1。
  5. get()方法返回裸指针。
  6. 不要用同一个裸指针初始化多个shared_ptr
  7. 不要用shared_ptr管理不是new分配的内存。

3)用于函数的参数

unique_ptr的原理相同。

4)不支持指针的运算(+、-、++、--)

二、更多细节

1)将一个unique_ptr赋给另一个时,如果源unique_ptr是一个临时右值,编译器允许这样做;如果源unique_ptr将存在一段时间,编译器禁止这样做。一般用于函数的返回值。

1 ) shared_ptr允许这样做。

2)用nullptrshared_ptr赋值将把计数减1,如果计数为0,将释放对象,空的shared_ptr==nullptr

3release()释放对原始指针的控制权,将unique_ptr置为空,返回裸指针。

3) shared_ptr 不存在释放的操作,控制权不是由一个人说了算的。

4std::move()可以转移对原始指针的控制权。还可以将unique_ptr转移成shared_ptr

5reset()改变与资源的关联关系。

pp.reset();        // 解除与资源的关系,资源的引用计数减1。

pp. reset(new AA("bbb"));  // 解除与资源的关系,资源的引用计数减1。关联新资源。

6swap()交换两个shared_ptr的控制权。

void swap(shared_ptr<T> &_Right);

7shared_ptr也可象普通指针那样,当指向一个类继承体系的基类对象时,也具有多态性质,如同使用裸指针管理基类对象和派生类对象那样。

8shared_ptr不是绝对安全,如果程序中调用exit()退出,全局的shared_ptr可以自动释放,但局部的shared_ptr无法释放。

9shared_ptr提供了支持数组的具体化版本。

数组版本的shared_ptr,重载了操作符[],操作符[]返回的是引用,可以作为左值使用。

10shared_ptr的线程安全性:

  1. shared_ptr的引用计数本身是线程安全(引用计数是原子操作)。
  2. 多个线程同时读同一个shared_ptr对象是线程安全的。
  3. 如果是多个线程对同一个shared_ptr对象进行读和写,则需要加锁。
  4. 多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,都需要加锁保护。

11)如果unique_ptr能解决问题,就不要用shared_ptr。unique_ptr的效率更高,占用的资源更少。

示例1:

#include <iostream>
#include <memory>
using  namespace std;

class AA
{
public:
      string m_name;

      AA() { cout << m_name << "调用构造函数AA()。\n"; }
      AA(const string & name) : m_name(name) { cout << "调用构造函数AA("<< m_name << ")。\n"; }
      ~AA() { cout << "调用了析构函数~AA(" << m_name << ")。\n"; }
};

int main()
{
      shared_ptr<AA> pa0(new AA("zqa"));     // 初始化资源zqa。
      shared_ptr<AA> pa1 = pa0;                       // 用已存在的shared_ptr拷贝构造,计数加1。
      shared_ptr<AA> pa2 = pa0;                       // 用已存在的shared_ptr拷贝构造,计数加1。

      cout << "pa0.use_count()=" << pa0.use_count() << endl;   // 值为3。

      shared_ptr<AA> pb0(new AA("zqb"));    // 初始化资源zqb。
      shared_ptr<AA> pb1 = pb0;                      // 用已存在的shared_ptr拷贝构造,计数加1。
      cout << "pb0.use_count()=" << pb0.use_count() << endl;   // 值为2。

      pb1 = pa1;      // 资源zqa的引用加1,资源zqb的引用减1。
      pb0 = pa1;      // 资源zqa的引用加1,资源zqb的引用成了0,将被释放。

      cout << "pa0.use_count()=" << pa0.use_count() << endl;   // 值为5。
      cout << "pb0.use_count()=" << pb0.use_count() << endl;   // 值为5。
}

2、智能指针的删除器

在默认情况下,智能指针过期的时候,用delete原始指针; 释放它管理的资源。

程序员可以自定义删除器,改变智能指针释放资源的行为。

删除器可以是全局函数、仿函数和Lambda表达式,形参为原始指针。

示例:

#include <iostream>
#include <memory>
using  namespace std;

class AA
{
public:
      string m_name;

      AA() { cout << m_name << "调用构造函数AA()。\n"; }
      AA(const string & name) : m_name(name) { cout << "调用构造函数AA("<< m_name << ")。\n"; }
      ~AA() { cout << "调用了析构函数~AA(" << m_name << ")。\n"; }
};

void deletefunc(AA* a) {    // 删除器,普通函数。
      cout << "自定义删除器(全局函数)。\n";
      delete a;
}

struct deleteclass               // 删除器,仿函数。
{
      void operator()(AA* a) {
            cout << "自定义删除器(仿函数)。\n";
            delete a;
      }
};

auto deleterlamb = [](AA* a) {   // 删除器,Lambda表达式。
      cout << "自定义删除器(Lambda)。\n";
      delete a;
};

int main()
{
      shared_ptr<AA> pa1(new AA("a"), deletefunc);
      //shared_ptr<AA> pa2(new AA("b"), deleteclass());
      //shared_ptr<AA> pa3(new AA("c"), deleterlamb);

      //unique_ptr<AA,decltype(deletefunc)*> pu1(new AA("1"), deletefunc);
    // unique_ptr<AA, void (*)(AA*)> pu0(new AA("1"), deletefunc);
      //unique_ptr<AA, deleteclass> pu2(new AA("2"), deleteclass());
      //unique_ptr<AA, decltype(deleterlamb)> pu3(new AA("3"), deleterlamb);
}

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

C++11新特性——智能指针之shared_ptr 的相关文章

  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • 如何使用 C# 中的参数将用户重定向到 paypal

    如果我有像下面这样的简单表格 我可以用它来将用户重定向到 PayPal 以完成付款
  • C 编程 - 文件 - fwrite

    我有一个关于编程和文件的问题 while current NULL if current gt Id Doctor 0 current current gt next id doc current gt Id Doctor if curre
  • “构建”构建我的项目,“构建解决方案”则不构建

    我刚刚开始使用VS2010 我有一个较大的解决方案 已从 VS2008 成功迁移 我已将一个名为 Test 的控制台应用程序项目添加到解决方案中 选择构建 gt 构建解决方案不编译新项目 选择构建 gt 构建测试确实构建了项目 在失败的情况
  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定

随机推荐

  • 0x0000000000指令引用的0x00000000内存。该内存不能为read

    1 不知道是某个软件导致 进入CMD命令提示符 输入for 1 in windir system32 ocx do regsvr32 s 1再输入 for 1 in windir system32 dll do regsvr32 s 1 2
  • 华为OD机试真题 Java 实现【文件目录大小】【2023 B卷 100分】,附详细解题思路

    目录 专栏导读 一 题目描述 二 输入描述 三 输出描述 四 解题思路 五 Java算法源码 六 效果展示 1 输入 2 输出 3 说明 4 再输入 5 再输出 6 说明 华为OD机试 2023B卷题库疯狂收录中 刷题点这里 专栏导读 本专
  • python竖线_python对齐竖线

    广告关闭 腾讯云11 11云上盛惠 精选热门产品助力上云 云服务器首年88元起 买的越多返的越多 最高返5000元 大多数编辑器都会自动对齐后续参数列表行 使其缩进程度与你给第一个参数列表行指定的缩进程度相同 def function na
  • Java web 学习笔记

    Java Web 1 web基础 1 1 基本概念 web开发 网页开发 分为 静态web 和 动态web 静态web 由 html css JavaScript 共同组成 提供给所有人看 数据永远不变 动态web 提供给所有人看的数组 在
  • Spring Security Oauth2系列(一)

    前言 关于oauth2 其实是一个规范 本文重点讲解spring对他进行的实现 如果你还不清楚授权服务器 资源服务器 认证授权等基础概念 可以移步理解OAuth 2 0 阮一峰 这是一篇对于oauth2很好的科普文章 需要对spring s
  • MySQL之常见的CRUD面试题【上】

    Welcome Huihui s Code World 接下来看看由辉辉所写的关于MySQL数据库的相关操作吧 目录 Welcome Huihui s Code World 导读 一 数据库的连表查询是什么 二 连表查询有几种常见类型 1
  • 架构-大数据架构-阿里

    大数据架构 大数据框架从0到1整个过程的实现 根据本博客内容 可以实现整个大数据基本搭建 只是大概步骤 供学习参考 本博客从下面5个方面介绍 技术框架 技术选型 系统架构设计 业务流程 生态实现步骤 以阿里为例的大数据架构 通过学习视频 然
  • html里面行高的原理,CSS行高(line-height)及文本垂直居中原理

    在CS多现业讲进行效通近年有务这行定果过近年有S中 line height 属性设置两段段文本之间的距离 也就是行高 如果我们把一段文本的line height设置为父容器的高度就可以实现文本垂直居中了 比如二 都过发宗发数前业很断屏击和公
  • 基于AAEncode编码的解密经历

    有天 正在干活 领导突然发了一个静态页面 说通过办公网流量获取的一个url 可以查询公司所有员工的靓照 截图如下 这极大的引发了我们安全部门的高度重视 立马对页面进行了分析
  • 关于RDF的技术支持和应用部分示例

    1 RDF的应用 Mozilla XUL XML User Interface http www mozilla org rdf doc faq html xul templates IBM ORIENT by IBM CRL http w
  • Linux读写GPIO的几种方法及一些有趣的应用

    Linux读写GPIO的几种方法及一些有趣的应用 Yihui 在智能音箱的设计中 最近在写LED的控制 触摸按键的检测 这不就是在Linux下读写GPIO 太简单吧 很多人就不屑一顾了 不过 简单读写IO也可以玩出花来 得到意外的惊喜 这里
  • 江苏省对口单招计算机原理,江苏省对口单招计算机原理教案

    第三章CPU 指令系统 总线系统 一 填空题 1 指令由 和 两部分组成 2 指令中的 指明完成操作所需要的操作数的地址 3 根据地址码部分所给出的地址的个数可将指令分为 二地址指令 三地址指令等 4 指令的寻址方式与操作数可存放的位置及存
  • springboot_读取自定义配置的两种方式

    一 核心配置文件 核心配置文件是指在resources根目录下的application properties或application yml配置文件 我们写自定义配置也一般写在这个文件里 但实际上我们为了方便区分和管理 我们可以自己新建一个
  • 从结果集中取出某一列的值组装成新的数组

    从结果集中取出某一列的值组装成新的数组 package main import fmt func main data map string string name z age 18 sex nan name l age 19 sex nv
  • 【导航算法】S型速度规划笔记

    S型速度规划笔记 一 S型速度规划逻辑整理 1 根据q1 q0和速度 判断是否在约束条件下 可以规划出S型速度规划 2 假设可以找到合适的S型速度规划 确定相应的参数v max和a max a 判断是否可以达到最大速度 v max 和加速度
  • Nacos用做配置中心时启动报错SocketTimeoutException http://localhost:8848

    当使用nacos作为注册中心时 很顺利 进如下配置 仅仅配置了ip和端口 启动类加 EnableDiscoveryClient注解 nacos作为配置中心 当继续将nacos作为配置中心时 添加加依赖
  • Oracle 中的外键约束

    一 前言 在Oracle数据库中 外键是用来实现參照完整性的方法之中的一个 打个比喻 外键是指定义外键的表的列的值必须在还有一个表中出现 被參照的表称之为父表 parent table 创建外键的表称之为子表 child table 子表中
  • Samba CentOS 7 安装

    安装步骤 Samba是在Linux与Windows系统间共享文件和打印机的标准协议 要在CentOS上安装Samba 可以按以下步骤操作 安装Samba相关包 yum install samba samba client samba com
  • 【Linux】SSH、shell

    最近GET到一个学习方法 了解一个新知识是什么的最快方法 就是去看它官网首页最大的那行字 一 比如SSH到底是什么 如下图 答案 SSH就是一个安全的shell应用程序 SSH是一个软件包 使系统登陆和文件传输都建立在一个安全的网络上 二
  • C++11新特性——智能指针之shared_ptr

    此课件及源代码来自B站up主 码农论坛 该文章仅作为本人学习笔记使用 1 智能指针shared ptr shared ptr共享它指向的对象 多个shared ptr可以指向 关联 相同的对象 在内部采用计数机制来实现 当新的shared