C++基础-智能指针
智能指针基础原理
智能指针和普通指针的区别在于智能指针实际上是对普通指针加了一层封装机制,这样的一层封装机制的目的是为了使得智能指针可以方便的管理一个对象的生命期,实现内存的自我回收。
对于普通的 局部变量(非静态局部变量),当离开它的作用域时,操作系统会自动将其释放。类对象在释放的时候是会自动调用该类的析构函数。
于是我们就想:如果是Test *t
不是一个普通的指针变量,而是一个类对象的话,并且在类的析构函数中实现了释放动态内存的步骤,那么只要该指针变量一退出作用域时就会调用析构函数,达到了释放动态内存的目的。这也就是智能指针的基本思想。
根据设想,在上篇文章最后一个示例程序的基础上可以自己实现一个最简易的智能指针:
1 |
|
运行结果:
1 | t->m_val100 |
C++11智能指针
四种智能指针
C++ STL为我们提供了四种智能指针:
( C++98提供,C++11建议弃用)auto_ptr
- 主要是用来解决最基本的资源自动释放问题
unique_ptr
- 可视作
auto_ptr
的替代品 - 持有对象的独有权,同一时刻只能有一个
unique_ptr
指向给定对象
- 可视作
shared_ptr
- 允许多个该智能指针共享堆中分配的内存(指向同一对象),通过引用计数实现管理
- 一旦最后一个这样的指针被销毁(计数变为0),该对象会被自动删除
weak_ptr
- 一般与
shared_ptr
配合使用,它可以从shared_ptr
构造,其构造和析构不改变引用计数 - 没有重载
->
和*
操作符,不能直接使用资源,需通过lock
函数取回一个shared_ptr
对象 - 作用是解决
shared_ptr
的循环引用问题,避免递归的依赖关系
- 一般与
基本使用方法
1 |
|
运行结果:
1 | pa-size:14 |
auto_ptr存在的问题
先来看如下代码:
1 | auto_ptr<int> px(new int(8)); |
上述赋值语句将两个指针指向同一内存地址,在析构时可能会被两个对象各自delete一次,而同一块内存是不能delete两次的。避免这种问题,主要有以下两种方法:
- 建立所有权概念。对于特定对象,同一时刻只能有一个智能指针可拥有, 最终只有拥有对象的智能指针的构造函数会删除该对象,
auto_ptr
和unique_ptr
就是采用这种策略 - 创建智能更高的指针,跟踪引用特定对象的智能指针个数,进行引用计数。
shared_ptr
采用这种策略
通过代码测试:
1 |
|
运行结果(只输出[1] *px = 10
并抛出异常):
1 | Expression : auto_ptr not dereferencable |
翻译过来是“表达式:auto_ptr不可撤销引用”?
单步调试可发现,当执行完赋值语句后,px的地址为empty,也就是空指针NULL,再去访问px当然会出错了。
如果将上述代码中的auto_ptr
换为unique_ptr
,在程序编译时就会提示错误,因而它可以在编译时将潜在的错误暴露出来:
1 | error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function |
如果将上述代码中的auto_ptr
换为shared_ptr
,程序可以正常运行:
1 | [1] *px = 10 |
因为shared_ptr
采用引用计数,当执行完赋值语句py = px
后,px
和py
都指向同一块内存,只不过在释放空间时因为事先要判断引用计数值的大小,因此不会出现多次删除一个对象的错误。
选择使用参考
如果程序中要使用多个指向同一个对象的指针,那么应该使用
shared_ptr
比如说现在有一个包含指针的STL容器,现在用某个支持复制和赋值操作的STL算法去操作该容器的指针元素,那么就应该用shared_ptr。不能用auto_ptr(行为不确定)或unique_ptr(编译时报错)。
如果程序中不需要使用多个指向同一个对象的指针,则可使用
unique_ptr
如果函数使用new分配内存,并返回指向该内存的指针,将其返回类型声明为unique_ptr是不错的选择。这样,所有权转让给接受返回值的unique_ptr,而该智能指针将负责调用delete。
在使用环境不支持C++11时,使用
auto_ptr
weak_ptr
可以避免auto_ptr的递归依赖关系
参考:
https://www.cnblogs.com/lsgxeva/p/7788061.html
https://blog.csdn.net/zsc_976529378/article/details/52250597