1.概念
智能指针是为了解决C中指针在动态分配内存过程中的内存泄露、悬空指针、野指针等问题所提出的C++标准类模板库。C11标准中放在
C++的智能指针包括:共享指针(std::shared_ptr),独占指针(std::unique_ptr),弱指针(std::weak_ptr)。
1.1 独占指针 unique_ptr
特点
独占所有权,同一时间只能有一个unique_ptr指向某个对象。不能复制,只能移动。
适用场景
当需要唯一控制一个对象时,例如管理动态数组或避免资源共享。
独占指针被禁止使用拷贝构造函数,仅能通过移动构造传递自身以保证指针所有权的唯一性。
使用方法
-
布尔转换
智能指针可以直接通过布尔值判断指针是否存在,和C中的指针一致。
if (ptr) {//do sth}; -
operator * 和operator ->
智能指针使用 * 和 -> 来访问智能指针的成员
*(ptr).func();ptr->func(); -
make_unique和new构造
C++中有两种使用智能指针的方式。
一种是通过std::unique_ptr<T>ptr = std::make_unique<T>(arg)直接创建堆上内存和智能指针。 另一种是通过std::unique_ptr<T> ptr(new(T)(arg))先申请内存得到野指针再创建智能指针,该方法下同时创建多个智能指针时可能会发生内存泄露。process_object(std::unique_ptr<MyClass>(new MyClass(1)), std::unique_ptr<MyClass>(new MyClass(2))); //后面的new抛出异常,此时第一个的智能指针会内存泄漏 -
get()
智能指针通过
ptr.get()来获得原始指针。
int * raw_ptr = ptr.get(); -
reset()
智能指针通过
ptr.reset()来释放当前对象,ptr自动指向nullptr。
ptr.get(); -
swap()
智能指针通过
swap()来交换两个unique_ptr的指向的内容,他们依然是独占的。
ptr1.swap(ptr2); -
release()
独占指针通过
ptr.release()来释放智能指针对一个内存的所有权,返回指向这个内存对象的裸指针。
int * released_ptr = ptr.release(); -
仅具有移动语义
独占指针通过移动语义的方式实现资源的独占传递,独占指针仅具有移动语义。
std::unique_ptr ptr1 = std::move(ptr2);
1.2 共享指针 shared_ptr
特点
共享所有权,多个shared_ptr可以指向同一个对象,通过引用计数跟踪使用情况。当计数为零时,自动释放内存。
适用场景
当多个部分需要共享访问同一个对象时。
循环计数问题: 当存在共享指针互相指向时,离开作用域时两边的共享指针都会因为引用计数不为0而不被释放。本质是类似死锁的现象,通过将其中的一个替换为weak_ptr解决。
使用方法
-
布尔转换
智能指针可以直接通过布尔值判断指针是否存在,和C中的指针一致。
if (ptr) {//do sth}; -
operator * 和operator ->
智能指针使用 * 和 -> 来访问智能指针的成员
*(ptr).func();
ptr->func(); -
make_unique和new构造
std::unique_ptr<T>ptr = std::make_unique<T>(arg)直接创建堆上内存和智能指针。
std::unique_ptr<T> ptr(new(T)(arg))先申请内存得到野指针再创建智能指针,可能会发生内存泄露。 -
get()
智能指针通过
ptr.get()来获得原始指针。
int * raw_ptr = ptr.get(); -
reset()
智能指针通过
ptr.reset()来释放当前对象,ptr自动指向nullptr。
ptr.get(); -
swap()
智能指针通过
swap()来交换两个shared_ptr的指向的内容,他们依然是独占的。
ptr1.swap(ptr2); -
use_count()
共享指针通过use_count()来获得指针的引用计数,从而实现在不存在使用内存的共享指针以后自动释放堆上内存。会导致循环计数,需要和weak_ptr配合使用。
ptr.use_count() -
owner_before() 共享指针通过owner_before()来判断两个共享指针或者弱指针是否使用同一个控制块(指向同一个堆内存,共享引用计数),若为false,则相同。
ptr.owner_before()
1.3 弱指针 weak_ptr
特点
弱引用,不增加引用计数。对指针内容是只读的,无对指针内容的修改能力,是一种对指针内容的观察者,与shared_ptr共用引用计数。用以解决shared_ptr的循环引用问题。weak_ptr不能直接从裸指针创建,没有make方法。
适用场景
避免循环引用导致的内存泄漏。
使用方法
-
布尔转换
智能指针可以直接通过布尔值判断指针是否存在,和C中的指针一致。
if (ptr) {//do sth}; -
依赖shared_ptr进行构造
弱指针是对指针内容只读的引用,不能通过裸指针直接构造,也没有make方法。
-
lock()
不能通过*或者->操作符直接访问成员,没有get方法获得裸指针。 当需要访问的修改指针内容时,弱指针通过weak_ptr.lock()升级为shared_ptr。
if (auto temp = weak.lock()){ //do sth } -
reset()
智能指针通过
ptr.reset()来释放shared_ptr当前对象,ptr自动指向nullptr。
ptr.get(); -
swap()
智能指针通过
swap()来交换两个weak_ptr的指向的内容,他们依然是独占的。
ptr1.swap(ptr2); -
use_count()
弱指针通过use_count()来获得指针的引用计数,弱指针不会增加引用计数。和shared_ptry一起配合使用可以解决循环计数问题。
ptr.use_count() -
owner_before()
共享指针通过owner_before()来判断两个共享指针或者弱指针是否使用同一个控制块(指向同一个堆内存,共享引用计数),若为false,则相同。
ptr.owner_before()