C++中的智能指针包括auto_ptr, unique_ptr, shared_ptr, weak_ptr. 其中 auto_ptr已被弃用.

unique_ptr

unique_ptr是大部分情况下的首选, 体现独占的语义. 当unique_ptr被销毁时, 其指向的原始指针也自动被销毁.

unique_ptr体现资源的独占, 因此无法被拷贝, 没有拷贝构造和拷贝赋值函数. 但是unique_ptr的所有权是可以通过move操作转移的, 由移动构造和移动赋值函数实现.

unique_ptr默认通过delete实现对象销毁. 你也可以在构造时指定unique_ptr的销毁函数.

使用默认的销毁函数时, unique_ptr的大小和原始指针相同. 使用自定义销毁器时, unique_ptr会将销毁器的类封装在unique_ptr中, 因此应尽量使用无状态的函数对象(没有捕获的lambda表达式或仿函数)作为销毁器, 此时unique_ptr的大小仍然和原始指针相同.

// 64bits platform

unique_ptr可以像原始指针那样用基类指针指向子类对象, 当然为了能正确析构对象, 你需要将析构函数声明为虚函数.

unique_ptr无法从原始指针隐式转换而来.

unique_ptr也可以用于数组对象 unique_ptr<T[]>, unique_ptr重载了[]操作符.

unique_ptr可以被隐式转换为shared_ptr, 因此一个工厂方法应尽量返回unique_ptr对象.

shared_ptr

shared_ptr体现共享的语义, shared_ptr从一个原始指针构造一个初始的对象, 并创建一个控制块. 从初始对象可以复制多个shared_ptr, 复制的对象共享控制块. 每个shared_ptr会使控制块中引用计数+1, 当所有shared_ptr被销毁时, 控制块中计数变为0, 原始指针亦被销毁.

从shared_ptr复制(拷贝构造和拷贝赋值)时会使引用计数+1, 移动时(移动构造和移动赋值)引用计数不变.

shared_ptr的大小是固定的2倍原始指针大小, 一个是指向原始指针, 一个指向控制块.

shared_ptr的控制块内存是动态分配的, 在首次创建初始shared_ptr对象时分配.

shared_ptr的引用计数增减必须是原子性的, 这会导致一些性能消耗.

和unique_ptr一样, shared_ptr也可以自定义销毁器. 但是不同的是, shared_ptr的销毁器是放在控制块内存中的, 不会影响shared_ptr的类型和本身的大小. 这也意味着你可以在同一容器中放置元素类型相同但销毁器不同的shared_ptr.

首次创建初始对象时会创建控制块内存. 因此, 需要避免从一个原始指针多次创建shared_ptr对象, 这样会导致原始指针被析构两次.

auto 

shared_ptr 同样适用于数组(c++17后).

weak_ptr

weak_ptr是shared_ptr的一个增强功能, 通常从shared_ptr创建. 不同的是, weak_ptr不会影响指向对象的引用计数.

weak_ptr使用expired()函数检查对象的引用计数是否为0, 即检查对应的shared_ptr是否过期.你可能会尝试这样使用weak_ptr:

auto 

这样检查shared_ptr是否过期, 然后使用weak_ptr. 但是在多线程情况下这样做可能有一些风险, 多线程下正确的方式是这样使用weak_ptr:

std

使用lock()返回一个shared_ptr, 然后使用返回的shared_ptr对象.

控制块中同样保存有weak_ptr的弱引用计数, 当控制块中的引用计数和弱引用计数都为0时, 控制块会被销毁.

enable_shared_from_this

很多情况下, 我们需要在一个对象内部使用包含this指针的shared_ptr对象, 或者从某个函数返回包含this指针的shared_ptr. 这时我们需要继承enable_shared_from_this, 然后用shared_from_this() 创建一个包含this指针的shared_ptr:

class 

enable_shared_from_this的原理是在enable_shared_from_this中存储了一个weak_ptr<Widget>对象. 当Widget对象被创建时, 这个weak_ptr置为指向nullptr. 当从一个Widget指针创建shared_ptr时, 会检测Widget对象是否继承了enable_shared_from_this. 如果继承了, 会将其内部的weak_ptr指向刚刚创建的shared_ptr.

这样, 这个weak_ptr就关联了一个包含this指针的shared_ptr, shared_from_this()其实就是从weak_ptr再次创建shared_ptr. 如果shared_from_this()前不曾用this创建过shared_ptr, weak_ptr就是指向nullptr的, 这时会抛出bad_weak_ptr异常.

make_shared

一般情况下, 更推荐使用make_shared来构造shared_ptr.

make_shared相对于直接从原始指针创建shared_ptr的优点有:

  1. 若创建原始指针和从原始指针创建shared_ptr之间抛出异常, 可能会发生内存泄漏;
  2. make_shared将对象的内存和控制块内存同时分配, 并同时释放. 这样可以提高执行效率.

缺点有:

  1. 无法使用大括号初始化;
  2. 无法自定义销毁器;
  3. 对象内存和控制块内存同时分配同时释放. 这会导致在shared_ptr的引用计数为0, 但weak_ptr引用计数不为0的情况下. 控制块内存无法释放, 会导致对象的那块内存一直无法释放, 造成内存浪费.

指针嵌套指针 拷贝_C++智能指针小结相关推荐

  1. C++智能指针详解【C++智能指针】

    自动内存管理 智能指针 什么是 RAII 原理 智能指针的模板(template)实现 auto_ptr auto_ptr 使用 重载函数 operator-> / *语法格式 自实现 auto ...

  2. 使用智能指针错误导致内存泄漏_C++智能指针使用的那些事

    指针指针的由来 在C/C++里面,内存管理由开发者自己管理.指针变量总是指向一片内存空间,这片内存空间可以是局部变量.也可以是通过malloc.new申请的.如果申请的内存没有释放,就会导致内存泄漏. ...

  3. bartender一行打印两个二次开发_C++ 智能指针和二叉树:图解层序遍历和逐层打印二叉树...

    作者:apocelipes  链接:https://www.cnblogs.com/apocelipes/p/10758692.html 二叉树是极为常见的数据结构,关于如何遍历其中元素的文章更是数不 ...

  4. unique函数_C++智能指针2:(虚?)析构函数(标准与实现的差异)

    只要是有良心的 C++ 教材,总是会苦心孤诣地告诫初学者,在继承关系中,应该把父类的析构函数定义成虚函数.这已然成为一条铁律,如果违背,不仅有内存泄漏的风险,在多继承情况下甚至会出现未定义行为.因此, ...

  5. c语言高低位拷贝_C语言指针详解

    1为什么使用指针 假如我们定义了 char a='A' ,当需要使用 'A' 时,除了直接调用变量 a ,还可以定义 char *p=&a ,调用 a 的地址,即指向 a 的指针 p ,变量 ...

  6. 对指针变量取地址_C语言指针简介(amp;和*运算符)

    取地址符(&) 和  取值符(*) (1)& 运算符 :用于取一个对象的地址 例如:int *p;    p = &c;    将c的地址赋值给指针变量p,我们称p为 &quo ...

  7. this指针作为函数参数_C++以指针作为函数参数(学习笔记:第6章 10)

    以指针作为函数参数[1] 为什么需要用指针做参数? 需要数据双向传递时(引用也可以达到此效果) 用指针作为函数的参数,可以使被调函数通过形参指针存取主调函数中实参指针指向的数据,实现数据的双向传递.( ...

  8. c++string 加引号_C++|引用计数与shared_ptr智能指针(以实现String类为例)

    C++ 中,动态内存的管理是通过一对运算符来完成的,new 用于申请内存空间,调用对象构造函数初始化对象并返回指向该对象的指针.delete接收一个动态对象的指针,调用对象的析构函数销毁对象,释放与之 ...

  9. 【C++11智能指针】shared_ptr的初始化、拷贝构造和拷贝赋值、移动构造和移动赋值

    文章目录 1.智能指针概述 2.shared_ptr的初始化 2.1 shared_ptr和new结合使用(直接初始化) 2.2 make_shared函数 3.shared_ptr的拷贝构造和拷贝赋 ...

最新文章

  1. DevExpress —— dxDataGrid
  2. linux luks源码,下载源代码编译安装
  3. 获取用户列表为空_Python中最常见的10个列表操作
  4. JDK7和JDK9流中异常的处理
  5. MMKV集成与原理,先收藏了
  6. Java 面试之数据结构
  7. 天逸310s可以装win7吗_婚车装饰是婚庆公司负责吗?婚车装饰还有哪里可以装
  8. 精选素材模板丨极简风简历模板
  9. 测试cpu的简单工具-dhrystone
  10. Angular Material 教程之布局篇 (五) : 布局参数
  11. pygarm windows 安装_飘云阁(PYG官方) Windows PowerShell实战指南(第2版)PDF - Powered by Discuz!...
  12. [算法课]算法课全题目解答及各周链接
  13. 暴风影音下载|暴风影音播放器下载
  14. Error C4668 : ‘USE_RTTI‘ is not defined as a preprocessor macro, replacing with ‘0‘ for ‘#if/#elif‘
  15. 原来 SQL 中的 NULL 是这么回事儿
  16. Win10 笔记本底下VM Ware鼠标失灵,不能点的问题解决
  17. python简单代码画皮卡丘-利用Python绘制萌萌哒的皮卡丘
  18. 如何调整Thinkpad x230的mini DP输出分辨率?
  19. 1.20 JQuery3:动画和特效
  20. 虹膜识别系统 python实现

热门文章

  1. 处理您的请求时发生错误(Web Dynpro ABAP)
  2. 银行IT迎“高景气”时代,宇信科技如何领跑行业?
  3. python integer_【Python】string/list/integer常用函数总结
  4. 机架搭建_【新阁教育】穷学上位机系列——搭建STEP7仿真环境
  5. 散点图 横纵坐标_厉害了,Matplotlib还能这样画散点图!
  6. iis 不是 php,iis是不是默认支持php
  7. BUUCTF--pwn picoctf_2018_buffer overflow 0
  8. BUUCTF(misc)变异凯撒 --二
  9. linux调用一个函数失败 打印错误,linux系统调用出错时的处理函数
  10. python函数名第一类方法、f-string格式化、迭代器及递归函数