c++ 之 shared_ptr

2023-11-11

/*
 * shared_ptr
 */
    shared_ptr 是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个 shared_ptrs 共同指向一个对象。
    这便是所谓的引用计数(reference counting)。

    一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。
    这在非环形数据结构中防止资源泄露很有帮助。


    类似 vector 智能指针也是模板。

        shared_ptr<string> p1;        // shared_ptr,可以指向string
        shared_ptr<list<int>> p2;   // shared_ptr,可以指向int的list

    智能指针的使用方法和普通指针类似,解引用返回它指向的对象,如果在一个条件判断中使用智能指针,效果就是检测它是否为空,

        // 如果 p1 不为空,检查它是否指向一个空 string
        if (p1 && p1->empty()) // p->mem -- (*p).mem
            *p1 = "ds"

/*
 * share_ptr 的拷贝和赋值
 */
    当进行拷贝或赋值操作时,每个 shared_ptr 都会记录有多少个其他 shared_ptr 指向相同的对象:

        auto p = make_shared<int>(42);        // p指向的对象只有p一个引用者
        auto q(p);                            // p和q指向相同对象,此对象有两个引用者

    可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)。
        
        无论何时拷贝一个shared_ptr,计数器都会递增;
        当给shared_ptr赋予一个新值或是shared_ptr被销毁时,计算器就会递减。
        
        一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象:

            auto r = make_shared<int>(42);    // r指向的int只有一个引用者
            r = q;    // 给r赋值,令它指向另一个地址
                      // 递增q指向的对象的引用计数
                      // 递减r原来指向对象的引用计数
                      // r原来指向的对象已没有引用者,会自动释放

 /*
  * share_ptr 自动销毁所管理的对象
  */
    当指向一个对象最后一个 share_ptr 被销毁时,share_ptr 类会自动销毁此对象。
    它是通过另一个特殊的成员函数——析构函数完成销毁工作的。

/*
 * shared_ptr 和 new 结合使用
 */
    可以使用 new 返回的指针来初始化智能指针,智能指针是一个类,分装了一个原始的 C++ 指针,用以管理所指对象的生命期。

    shared_ptr<double> p1;                // shared_ptr可以指向一个double
    shared_ptr<int> p2(new int (42));   // p2指向一个值为42的int

    接受指针参数的智能指针构造函数是 explicit 的。
    因此,我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针:

    shared_ptr<int> p1 = new int(1024);    //错误:必须使用直接初始化形式
    shared_ptr<int> p2(new int (1024));    //正确:使用了直接初始化

    出于相同的原因,一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针:

        shared_ptr<int> clone(int p) {
            return new int(p);                    //错误:隐式转换为shared_ptr<int>
        }

        shared_ptr<int> clone(int p) {
            return shared_ptr<int>(new int(p)); //正确:显式地用int*创建shared_ptr<int>
        }

    默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。
    可以将智能指针绑定到一个指向其他类型的资源的指针上,但是为了这样做,必须提供操作来代替  delete 。

/*
 * weak_ptr
 */
    weak_ptr是为配合shared_ptr而引入的一种智能指针。

    weak_ptr可以从一个shared_ptr或另一个weak_ptr对象构造,
    它的构造和析构不会引起shared_ptr引用记数的增加或减少(但会导致引用计数区域内负责weak_ptr计数变量_M_weak_count的增加或减少,
    当其计数为0时,调用_M_destroy()释放对象内存)。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象。

    weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己,
    但助手类enable_shared_from_this的shared_from_this会返回this的shared_ptr,只需要让想被shared_ptr管理的类从它继承即可。


/*
 * example
 */
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
 
struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // 注意:此处非虚析构函数 OK
    ~Base() { std::cout << "  Base::~Base()\n"; }
};
 
struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // 线程安全,虽然自增共享的 use_count
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 
    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // 从 main 释放所有权
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();
    std::cout << "All threads completed, the last one deleted Derived\n";
}

#if 0
  Base::Base()
  Derived::Derived()
Created a shared Derived (as a pointer to Base)
  p.get() = 0x56072b522260, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
  p.get() = 0, p.use_count() = 0
local pointer in a thread:
  lp.get() = 0x56072b522260, lp.use_count() = 6
local pointer in a thread:
  lp.get() = 0x56072b522260, lp.use_count() = 4
local pointer in a thread:
  lp.get() = 0x56072b522260, lp.use_count() = 2
  Derived::~Derived()
  Base::~Base()
All threads completed, the last one deleted Derived
#endif

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

c++ 之 shared_ptr 的相关文章

随机推荐

  • 7-3 两个有序链表序列的合并 (20 分)

    已知两个非降序链表序列S1与S2 设计函数构造出S1与S2合并后的新的非降序链表S3 输入格式 输入分两行 分别在每行给出由若干个正整数构成的非降序序列 用 1表示序列的结尾 1不属于这个序列 数字用空格间隔 输出格式 在一行中输出合并后新
  • Redis之十大类型(三)(下)

    3 6 Redis位图 bitmap 由 0 和 1 表示的二进制位的 bit 数组 介绍 用String类型作为底层数据结构实现的一种统计二值状态的数据类型 位图本质是数组 它是基于String数据类型的按位的操作 该数组由多个二进制位组
  • 机器学习之K-means原理详解、公式推导、简单实例(python实现,sklearn调包)

    目录 1 聚类原理 1 1 无监督与聚类 1 2 K均值算法 2 公式推导 2 1 距离 2 2 最小平方误差 3 实例 3 1 python实现 3 2 sklearn实现 4 运行 可直接食用 1 聚类原理 1 1 无监督与聚类 在这部
  • 图像处理中常用数学知识

    2 3 3 赋范空间 每个实数或复数 都有相对应的绝对值或者模 每一个n维矢量 也都可以定义其长度 如果把 长度 的概念推广到一般抽象空间中的元素上 就可以得到范数这个概念 本节完 2 3 6 希尔伯特空间 定义 在由内积所定义的范数意义下
  • windows的cmd常用命令

    文章目录 一 位 二 cmd基本操作 1 win R启动运行 2 打开cmd 3 运行的命令 三 cmd常用命令 1 功能性命令 2 文件操作 3 shutdown 4 tasklist命令 5 taskkill命令 6 查看日志 四 cm
  • vue项目启动Error: Cannot find module ‘imagemin-gifsicle‘

    Error Cannot find module imagemin gifsicle 依赖没有安装完全 可以删除module 然后重新安装依赖
  • C语言学习:平方-->乘方(m的n方)

    平方 直接用两个数 或变量 相乘就可以表示平方 比如x x 不过如果 需要求m的n次方 就需要用到pow x y 乘方 包括开方 这个库函数了 使用pow x y 这个库函数 需要math h头文件 其中x和y都是双精度浮点 double
  • [FPGA开发]解决正点原子Xilinx下载器无法下载、灯不亮的问题

    问题描述 使用正点原子的Xilinx下载器下载时 电脑无法识别下载器 Vivado无法识别开发版 问题解决 1 检查XIlinx下载器的灯是否亮起 亮灯 说明 解决方法 红灯亮起 下载器可以连接到PC 检查开发版是否供电正常 蓝灯亮起 下载
  • pytorch测试模型时根据不同列别的概率值得到具体的分类

    pytorch 分类任务的教程 https pytorch org tutorials beginner blitz cifar10 tutorial html 主要使用的是 predict torch max out data 1 最后的
  • best ajax lib,BEST Currency Converter

    想提升客户的购物体验 以当地货币显示价格可以省去他们很多不必要的时间 也能提升客户与平台的粘度 该插件具备如下优势 1 轻松添加多种货币 按下按钮即可添加160多种货币 像专业人士一样开始国际销售 并鼓励客户购买 2 自动转换价格 价格会根
  • node.js 读取文件的时候 cmd执行脚本,中文(汉字)打印不出来

    node js 读取文件的时候 cmd执行脚本 中文 汉字 打印不出来 文本详情 输出结果 问题原因 txt编码格式不是UTF 8 解决办法 打开TXT文件 点击 文件 gt 另存为 gt 编码改为UTF 8 保存替换 问题解决
  • 【大数据】Flink 详解(五):核心篇 Ⅳ

    本系列包含 大数据 Flink 详解 一 基础篇 大数据 Flink 详解 二 核心篇 大数据 Flink 详解 三 核心篇 大数据 Flink 详解 四 核心篇 大数据 Flink 详解 五 核心篇 大数据 Flink 详解 六 源码篇
  • 通俗易懂的教你编写自己的webpack loader与plugin

    前言 webpack几乎是目前前端开发者无人不知的打包框架 毕竟无论使用什么开发库 都会想到要使用webpack打包 包括各种脚手架cli工具 大部分也采用了webpack作为其打包工具 本文试图用最简单的代码 仅仅使用命令行工具 代码足够
  • spring data jpa使用limit时,抛QuerySyntaxException unexpected token: limit

    异常重现 jpql语句如下 select g from Entity g where g codeUrl codeUrl ORDER BY g createTime DESC limit 1异常原因 limit是特定于某些数据库 例如 my
  • IDEA设置为中文

    按照如下步骤操作即可 下载对应的语言包 中文语言包下载地址 注意此处下载的版本只能是IDEA版本之前的语言包 下载之后的会报错 将下载好的jar包 放在IDEA目录下的lib目录下 点击File Settings 点击Plugins 然后点
  • matlab相关性分析(皮尔逊,肯德尔,斯皮尔曼)

    代码 clc clear load CRO C3 mat data GPP DT VUT REF EVI NDVI NIRv kNDVI LSWI FPAR TA F VPD F SW IN F rho corr data type pea
  • LeetCode题目笔记——1658. 将 x 减到 0 的最小操作数

    文章目录 题目描述 题目难度 中等 方法一 反向思考 双指针求最长子数组 代码 Python 代码 C 方法二 滑动窗口 代码 总结 我把这篇也归到面试题那一栏 因为觉得这题的思路和思考方式还挺好的 或许能用到其他题上 题目描述 给你一个整
  • [创业之路-74] - 感悟 - 创业是所有因素的机缘组合,缺一不可; 舰船思维 VS 城堡思维.

    感悟 方向 趋势 路径 资助 船只 船长 大副 水手 船员 装备 配套 路径 一个都不能少 只看对方向与趋势 一样葬身在趋势的洪流中 看不对方向与趋势 亦会老死在寂寞孤冷之中 在所有因素中 船只 装配 配套是最表象和最容易触发感官体验的 目
  • 服务器与虚拟技术,云服务器与虚拟化服务器的区别

    虚拟化服务器是让一台服务器变成几台甚至上百台相互隔离的虚拟服务器 不再受限于物理上的界限 而是让CPU 内存 磁盘 I O等硬件变成可以动态管理的 资源池 从而提高资源的利用率 简化系统管理 服务器虚拟化的种类 主要有 一虚多 多虚一 和
  • c++ 之 shared_ptr

    shared ptr shared ptr 是一种智能指针 smart pointer 作用有如同指针 但会记录有多少个 shared ptrs 共同指向一个对象 这便是所谓的引用计数 reference counting 一旦最后一个这样