C++ 智能指针

什么是智能指针

智能指针是自动帮你管理内存、防止内存泄漏的包装类,是现代 C++ 用来代替裸指针的工具,解决了裸指针在某些地方的痛点。比如:

1.忘记 delete ,导致内存泄漏。

2.提前 delete ,后面还要继续用,导致悬空指针,野指针。

3.异常抛出时,函数提前退出,delete 永远执行不到。

RAII

要了解智能指针,我们先从它的设计思路开始。智能指针的设计思路是 RAII (Resource Acquisition Is Initialization),这是一种 "资源获取即初始化" 的编程思想,是所有智能指针的底层原理,也是现代 C++ 管理资源的核心范式。

RAII 的核心逻辑是:把资源的生命周期,和一个栈对象的生命周期绑定在一起 。RAII 在获取资源时把资源委托给一个对象,接着控制对资源的访问,资源在对象生命周期内始终保持有效,最后在对象析构的时候释放资源,这样保障了资源的正常释放,避免资源泄漏问题

C++标准库智能指针的使用

使用智能指针需要包含头文件 <memory>

C++98:

智能指针在 C++98 就已经出现,但效果不尽人意。

auto_ptr:auto_ptr是 C++98 就出现的智能指针,但它的设计十分糟糕,属于 C++ 的一次失败的尝试。它的逻辑是:拷贝时,把拷贝对象的资源的管理权转移给拷贝对象,旧的对象会被置空。但这种置空是不会显示表现出来的,让人以为旧指针能用,如果此时访问就会报错。

C++11:

之前 C++98 搞出来的智能指针太糟糕,很多公司明令禁止使用。C++ 委员会也知道只是一个非常差劲的设计,于是在 C++11 移动语义出现后,迅速抛弃了 auto_ptr,搞出了几个新的智能指针。

unique_ptr: unique_ptr 不支持拷贝,只支持移动。unique_ptr 也会把旧的指针置空,但它的移动是显示的,也就是说你在使用它时你应该自己清楚旧指针会被置空,如果你还去访问旧指针就是你自己的问题了。在不需要拷贝的场景建议使用它。

shared_ptr :shared_ptr 支持拷贝,也支持移动。它的底层是使用引用计数的方式实现的。shared_ptr 除了支持用指向资源的指针进行构造,还支持用 make_shared 用初始化资源对象的值直接构造。

weak_ptr: weak_ptr 完全不同于以上指针,它不支持 RAII ,这也意味着不能用它直接管理资源。weak_ptr 的产生是为了解决循环引用的问题,这个后面细讲。

智能指针析构时默认进行 delete 释放资源,所以如果不是 new 出来的资源,交给智能指针管理会崩溃。智能指针支持在构造时给一个删除器,在它调用析构时会调用删除器去释放资源,这解决了不同 delete 的需求。

循环引用

循环引用问题出现在 shared_ptr 上,它会导致资源没有得到释放,内存泄漏,想要解决这个问题,需要用到 weak_ptr 。

先看例子:现在有 n1 和 n2 两个 shared_ptr:

假如 n1 的资源中又有一个shared_ptr 指针 _next 指向 n2,n2 的资源中又有一个shared_ptr 指针 _prev 指向 n1。注意此时计数器的变化:

当我们析构 n1 和 n2 时, 按理说资源应该被释放,但是 share_ptr 的资源释放是看的计数器释放为空,所以此时资源不会被释放:

这很显然并不符合实际需求,会导致内存泄漏。

weak_ptr 可以很好地解决这个问题。前面说过:weak_ptr 不支持 RAII 。它不支持绑定资源,只支持绑定 shared_ptr ,所以它不会增加 shared_ptr 的引用计数,我们将上面的 _next 和 _prev 指针设置为 weak_ptr 指针,就可以解决循环引用问题。

("来源:cplusplus.com")

weak_ptr 没有重载 operator* 和 operator-> 等,因为它不支持绑定资源,所以用它去访问资源是危险的,但它支持 expired 检查指向的资源是否过期,use_count 也可以获取 shared_ptr 的引用计数。weak_ptr 想访问资源时,可以调用 lock 返回一个管理资源的 shared_ptr ,如果资源已经被释放,返回的 shared_ptr 是一个空指针,如果没有释放,则通过返回的 shared_ptr 访问资源就行。

相关推荐
Chloeis Syntax12 小时前
JavaEE初阶学习日记(1)---线程和进程
java·开发语言·学习·线程·javaee
时空自由民.12 小时前
C/C++ volatile关键字原理及应用介绍
java·c语言·c++
凯瑟琳.奥古斯特12 小时前
SpringBoot快速入门指南
java·开发语言·spring boot·后端·spring
我头发还没掉光~12 小时前
P4147 玉蟾宫
数据结构·c++·算法
江屿风12 小时前
【c++笔记】类和对象流食般投喂(上)
开发语言·c++·笔记
xyq202412 小时前
Lua 模块与包
开发语言
是个西兰花12 小时前
单列模式和C++中的类型转换
c++·单例模式·设计模式·rtti
小短腿的代码世界12 小时前
打印不止是QPrinter:深入Qt Print Support框架的内核设计与跨平台输出管道
开发语言·qt
性野喜悲12 小时前
python将excel中的链接转成图片并替换链接展示在excel中【将pdf的第一页插入excel并将对应信息获取到插入签名等位置】
开发语言·python·excel
诙_13 小时前
C++代码实践应用
开发语言·c++