智能指针

来源视频: 独占智能指针unique_ptr使用技巧_哔哩哔哩_bilibili

本文文件下载

image这里第三点指的是多线程的情况. 即当多个线程共享一个对象的时候, 程序员难以确定何时释放.

独占指针 unique_ptr

image

image

示例

image

上述程序, 只会调用构造函数. 我们没有手动 delete 的话, 不会调用析构函数. 此时, 我们使用独占指针管理指针 p:

image

这个语句的意思是: 独占指针的管理的对象的类是 AA, 使用 pu1 管理AA类型指针 p.

这样程序就会在结束的时候执行析构函数.

原理: 独占指针对象 pu1在被销毁的时候会执行自身的析构函数, 而在自身的析构函数中会 delete p. 从而调用了 p 所指对象的析构函数.

使用 pu1 的方式和普通指针基本一样:

image

实际上, 独占指针有三种初始化方法:

image

一般使用第一种.

感觉好像有了智能指针, 就没必要再用普通指针了0.0

独占指针的类定义

image

初始化的时候不可以使用赋值运算符将普通指针赋给独占指针(显然, 这个过程存在类型转换).

image

image

在拷贝函数后面加了 = delete, 显式告诉编译器不要提供拷贝构造函数. 否则编译器会自动提供. (cpp11新语法)

imageimage

不可使用赋值拷贝.

禁用拷贝构造函数和赋值函数的原因是, 防止出现多个独占指针管理同一个普通指针的情况. 举个例子, 假如有两个独占指针指向了同一个普通指针, 在程序结束的时候, 两个指针都会执行自身的析构函数, 结果就是连续对该普通指针执行了两次 delete, 产生错误结果.

然而, 这样依旧阻止不了犯错的可能. 因为我们依旧可以用一个裸指针初始化多个独占指针, 从而导致上述问题.

image

这个例子也告诉我们, 第一种初始化方法更安全.

get()​ 方法可以返回独占指针所管理的裸指针.

一个小细节: 直接输出 pu1, 输出结果是 p 指向的地址. 输出 &pu1, 才是 pu1 自身的地址. 对的, pu1 本身有它自己的地址, 不要忘了.

在函数调用中, 只能传独占指针的引用给函数, 不能传值, 这是因为独占指针禁用了拷贝构造函数. 另一种方案是传裸指针给函数. 这个方案在技巧中会提.

智能指针不支持指针的运算 (+ - ++ --).

使用技巧

image

也就是有两种情况能够赋给另一个: 临时变量 和 函数返回值.

image

可以认为虽然删除了独占指针的赋值函数, 但是编译器为这两种情况做了特别处理.

image

image

两个点:

  1. 将 nullptr 赋给 pu 后将释放 pu 先前管理的对象;
  2. 此后 pu 的值为 nullptr.

imageimage

用于应对不同的场景.

image

像这种需要原始指针, 但又不负责 delete 的函数, 使用 .get() 方法传给它

image

image

这种就用 release 方法.

image

image

最常见的情况. 直接传 pu 给它即可.

image

注意, 这里使用的是值传递.

image

不过我认为这第四种情况出现的可能性还是非常小, 如果出现了大概率是忘记用引用了.

image

image

image

image

image

注意语法: AA[] (实际上改成 AA* 应该也没问题). 之后要访问数组内的元素, 跟正常的数组差不多, 用下标运算符即可.

共享指针 shared_ptr

image

基本用法和独占指针差不多, 区别在于共享指针可以多个管理一个, 独占指针只能一个管理一个. 也因此, 共享指针没有删除拷贝构造函数和赋值函数

可用 p0.use_count()​ 来获取引用计数.

image

image

推荐第二种, 因为 cpp11 就已经提供, 而独占指针在 14 才提供.

image

image

image

image

共享指针没有 release() 方法, 因为是否释放对原始指针的控制权不由某一个共享指针决定.

image

但是反过来不行.

image

其他大部分使用和独占指针没什么区别

image

image

智能指针的删除器

image

在没有自定义删除器的情况下, 默认的删除器就是只执行 delete 操作.

image

image

在初始化的时候指定删除器即可.

在自定义删除器中也可以不执行 delete 操作, 当然后果自负了.

image

这俩没学过. 是仿函数和 lambda 表达式的知识点.

image

等价的初始化方式

image

弱智能指针 weak_ptr

image

image

image 一般来说, 用 weak_ptr 访问资源的方式为: 先用 expired 判断是否过期, 然后用 lock 返回共享指针, 再对这个共享指针操作即可.

以上这个使用方法是错误的, 因为在多线程中这个操作并非原子操作, 不安全. 有可能在判断完 expired 的下一刻, 正好就 expired 了, 然后继续执行了后面的语句.

正确的方法为: 直接用 lock 得到共享指针, 将其赋给另一个共享指针, 然后用 if 语句来判断这个共享指针是否为 nullptr, 如果不是就进行操作.

image