早在C++98/03标准的时候,C++就引入了智能指针(Smart Pointer)的概念来帮助程序员对于堆内存进行自动回收。
引入的目地主要是:对指针的行为进行一定的规范。这有很多的好处,比如:
- 这样可以避免野指针的出现
- 这样可以避免错误的对于同一块地址进行两次释放
- 释放不在使用的内存资源,避免内存的泄漏.
智能指针使得为我们能够更加安全有效的使用(共享)同一块堆空间.
shared_ptr的实现
C++ 智能指针是采用的 引用计数(Reference counting) 的方式实现的。更简单的说,智能指针会负责维护一个整形值用于标记当前空间的引用值。当有新的对象使用同一块堆内存时,整形值加一。当使用该块堆内存的对象被释放掉时,整形值减一。当这个值减少为0时,则表示除了不在会有对象使用这块内存,该堆空间会被释放掉(而不用程序员担心什么时候释放)。
1 | // std::shared_ptr采用的是模板类的方式定义的,它继承自std::_shared_ptr 这个类(shared_ptr_base.h文件中). |
shared_ptr继承自_shared_ptr,在这个类中维持了两个对象,一个是element_type类型的指针_M_ptr,一个是__weak_count<_Lp>类型的计数器_M_refcount。通过对这两个对象的维护,实现智能指针的目的.
例如,use_count()函数借助_M_refcount直接返回的引用数。
1 | long use_count() const noexcept{ |
如何使用智能指针
C++11中提供了三种智能指针:std::shared_ptr, std::unique_ptr, std::weak_ptr,使用时需添加头文件
C++98/03 标准中,曾经支持使用 auto_ptr 智能指针来实现堆内存的自动回收,但后来在C++17被废除.
下面以shared_ptr为例,介绍C++中智能指针的使用.
shared_ptr的构造方法
shared_ptr 这个类为我们提供了十几种创建共享指针的构造方法.
1 | // 我们能够通过以下的方式来创建 shared_ptr 指针 |
shared_ptr智能指针的释放和内存的释放
以下的两种情况会导致内存的释放:
- 最后一个拥有该块堆内存的shared_ptr指针被销毁时.
- 最后一个拥有该对象的shared_ptr通过操作符=或reset()被分配另一个指针时。
智能指针除了为我们提供了默认的内存释放规则,还允许我们自定义内存释放的规则.
1 | //指定 default_delete 作为释放规则 |
其他方法
shared_ptr 是继承的__shared_ptr 这个类.
这个基类为我们提供了以下的一些方法:
方法名 | 说明 | 返回类型 |
---|---|---|
get() | 获得当前智能智能指向元素的普通指针 | element_type* |
user_count() | 当前堆内存空间的引用量 | long |
unique() | 当前堆内存是否还有其他引用 | bool |
swap() | 交换两个智能指针 | void |
reset() | 没有参数时,当前智能指针变为空智能指针,有参数时当前智能指针指向给定的新内存空间,原内存引用值减1,当前内存引用值置1 | void |
shared_ptr,unique_ptr, std::weak_ptr之间的区别
shared_ptr能够实现多个shared_ptr类型的指针“共享”使用同一块堆内存,当有一个指针放弃该堆内存的“使用权”时,也不会影响其他指向该堆内存的shared_ptr空间.只有当引用计算变为0时,才会释放掉这一块堆内存空间.
unique_ptr 通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。、
std::weak_ptr 用来表示对于std::shared_ptr 管理的对象的弱引用. 用来表达临时所有权的概念,当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,std::weak_ptr 用来跟踪该对象。此外值得注意的是:weak_ptr 类型指针并不会影响所指堆内存空间的引用计数。
参考
http://c.biancheng.net/view/7898.html
https://en.cppreference.com/w/cpp/memory/shared_ptr