C++:智能指针shared_ptr、unique_ptr、weak_ptr的概念、用法即它们之间的关系

智能指针

(1)概述

A.Why(C++为什么引入智能指针)

C++引入智能指针的根本原因就是解决手动管理动态内存所带来的问题,手动管理动态内存常见的问题如下:内存泄漏、悬挂指针、释放操作未定义等

内存泄漏问题:

当程序用光了它可用的动态内存空间,new就会报错

int *p = new int; //*p的值未定义
int *p2 = new int(); //*p的值初始化为0
//程序用光了它可用的堆内存空间
int *pn = new int; //此时将会抛出异常:std::bad_alloc
int *pn_noThrow = new (nothrow) int; //如果分配失败,将返回空指针nullptr

悬挂指针问题:

当使用delete释放了指向动态内存空间的指针p时,指针p就成为了一个悬挂指针(即在有的机器中,指针p还保存着曾经的内存地址),因此在手动管理动态内存空间的时候,一定要在delete之后将对应指针置为nullptr或0

int *ptr = new int();
delete ptr;
ptr = nullptr; //避免悬挂指针从而引起的未定义定位(不可预知行为)

释放操作未定义问题:

释放一块非new分配的内存或将相同的指针释放多次,其行为是未定义的

B.What(什么是智能指针)

本质是一个封装了原始指针的模板类,在适当的时候(生命周期结束时)自动释放所管理的动态内存

C.Which(有哪些智能指针)

  • shared_ptr
  • weak_ptr
  • unique_ptr
智能指针 所有权 内存释放
shared_ptr 多个 std::shared_ptr 共享所有权 通过内部的引用计数机制,当引用计数为 0 时,自动释放内存
weak_ptr 不拥有所指向对象的所有权,它只是对 std::shared_ptr 的一种弱引用 -
unique_ptr 独占所有权 当 std::unique_ptr 超出其作用域时,自动释放所管理的内存

(2)How(如何使用智能指针)

C++中的智能指针,其本质都是类模板,因此在学习智能指针的时,我们可以像对待普通类对象一样使用智能指针对象。正是因为它的本质是类对象,因此使用智能指针的一般流程如下:创建智能指针对象和调用智能指针对象的方法

A.智能指针类的成员变量

shared_ptr智能指针:

成员数据 说明
T *ptr 存放实际数据的动态内存地址
int iCount 计数器,用于记录有多少个shared_ptr共享同一块内存空间
deleter 删除器,本质是一个函数对象,自定义资源释放的行为

unique_ptr智能指针:

成员数据 说明
T *ptr 存放实际数据的动态内存地址
deleter 删除器,本质是一个函数对象,自定义资源释放的行为

weak_ptr智能指针:

weak_ptr 是一种不控制所指向对象生存期的智能指针,它指向由一个 shared_ptr 管理 的对象。将一个 weak_ptr 绑定到一个 shared_ptr 不会改变 sharedptr 的引用计数。一 旦最后一个指向对象的 shared_ptr 被销毁,对象就会被释放。即使有 weakptr 指向对象, 对象也还是会被释放,因此,weak_ptr 的名字抓住了这种智能指针“弱”共享对象

所以说weak_ptr可以说没有成员数据

B.智能指针类的成员函数

shared_ptr智能指针:

成员函数 说明
constexpr shared_ptr() noexcept = default; 默认的构造函数
constexpr shared_ptr(nullptr_t) noexcept {} 带空指针的构造函数
explicit shared_ptr(T* ptr) 传入指向堆内存的一般指针
void swap(shared_ptr& _Other) noexcept 交换两个智能指针所管理的内存
void reset() noexcept 释放资源
remove_extent_t<_Ty>* get() const noexcept 得到所管理动态内存的地址
bool unique() const noexcept 是否只有一个引用
long use_count() const noexcept 返回shared_ptr对象的引用数

在这里插入图片描述

unique_ptr智能指针:

成员函数 说明
constexpr unique_ptr() noexcept 默认的构造函数
constexpr unique_ptr(nullptr_t) noexcept 带空指针的构造函数
explicit unique_ptr(pointer _Ptr) noexcept 传入指向堆内存的一般指针
void swap(shared_ptr& _Right ) noexcept 交换两个智能指针所管理的内存
_Dx& get_deleter() noexcept 得到删除器对象
pointer release() noexcept 释放所管理动态内存的地址
void reset(pointer _Ptr = nullptr) noexcept 如果reset函数带有参数,则会释放当前指向的对象,并将unique_ptr指向新的对象

在这里插入图片描述

weak_ptr智能指针:

成员函数 说明
constexpr weak_ptr() noexcept = default; 默认的构造函数
weak_ptr(const weak_ptr& _Other) noexcept 拷贝构造函数
weak_ptr(const shared_ptr<_Ty2>& _Other) noexcept 带shared_ptr对象的构造函数
void swap(weak_ptr& _Other) noexcept 交换两个智能指针所管理的内存
void reset() noexcept 释放资源
bool expired() const noexcept use_count()为0时返回true
shared_ptr<_Ty> lock() const noexcept 转为shared_ptr对象
long use_count() const noexcept 返回对应shared_ptr对象的引用数

在这里插入图片描述
在这里插入图片描述

(3)使用智能指针需要注意的事项

  • 不要混合使用常规指针和智能指针

    使用内置指针访问智能指针管理的对象是危险的,无法知道对象何时被销毁

  • 不要使用get()函数初始化另一个智能指针或为另一个智能指针赋值
    在这里插入图片描述

  • 不 deleteget()返回的指针

  • 不使用相同的内存指针初始化(reset)多个智能指针

  • 如果智能指针所管理的内存不是 new 分配的内存,要传递一个删除器


================================================================================
若读者对C++感兴趣,欢迎阅读C++知识点总结系列,攘括C++所有的基础知识,入口如下:

C++知识点总结全系列文章索引:
【C++知识点总结全系列 (01)】:数据类型、数据类型转换和变量
【C++知识点总结全系列 (02)】:C++中的语句、运算符和表达式详细总结
【C++知识点总结全系列 (03)】:函数(函数参数传递、可变参数、函数返回值等详细介绍)
【C++知识点总结全系列 (04)】:C++类的详细总结与分析
【C++知识点总结全系列 (05)】:IO 类的详细总结和分析
【C++知识点总结全系列 (06)】:STL六大组件总结- 配置器、容器、迭代器、适配器、算法和仿函数
【C++知识点总结全系列 (07)】:模板与泛型编程详细总结与分析
【C++知识点总结全系列 (08)】:面向对象编程OOP


最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 16:46:01       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 16:46:01       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 16:46:01       57 阅读
  4. Python语言-面向对象

    2024-07-18 16:46:01       68 阅读

热门阅读

  1. python 请求https api, header参数的设置

    2024-07-18 16:46:01       24 阅读
  2. 文件上传obs服务器

    2024-07-18 16:46:01       22 阅读
  3. C++运算符重载(+)

    2024-07-18 16:46:01       21 阅读
  4. 使用Dockerfile构建镜像

    2024-07-18 16:46:01       20 阅读
  5. python开发基础——day14 模块与包

    2024-07-18 16:46:01       23 阅读
  6. 【国内当前可用pip&conda源刷新】

    2024-07-18 16:46:01       19 阅读
  7. 解决浏览器缓存导致获取不到最新前端代码问题

    2024-07-18 16:46:01       21 阅读
  8. 6Python的Pandas:数据读取与输出

    2024-07-18 16:46:01       22 阅读
  9. linux修改时区为CST

    2024-07-18 16:46:01       17 阅读
  10. 请求通过Spring Cloud Gateway 503

    2024-07-18 16:46:01       18 阅读
  11. 使用小皮面版的Nginx服务搭建本地服务器

    2024-07-18 16:46:01       21 阅读
  12. Jenkins 安装、部署与配置

    2024-07-18 16:46:01       23 阅读