浅谈智能指针
前情提要
野指针(Wild Pointer): 野指针是指指向任意未知位置的指针,它没有被初始化或者指向无效的内存。
悬挂指针(dangling pointer):指指向已释放或无效内存的指针。当一个指向动态分配内存的指针所指向的内存被释放后,该指针仍然保留着原来的指向,但此时使用该指针访问所指向的内存将导致未定义的行为。
RAII (Resource Acquisition Is Initialization): 资源获取即初始化, R使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。像下面的例子:
1 | class str_ { |
智能指针
因为C++使用内存的时候很容易出现野指针、悬空指针、内存泄露等问题。所以C++11引入了智能指针来管理内存。使用智能指针(如std::unique_ptr
、std::shared_ptr
)来自动管理资源生命周期,避免手动释放内存和引入悬垂指针和野指针问题。共有四种智能指针:
auto_ptr
:已经不用了unique_ptr
:独占式指针,同一时刻只能有一个指针指向同一个对象shared_ptr
:共享式指针,同一时刻可以有多个指针指向同一个对象weak_ptr
:用来解决shared_ptr
相互引用导致的死锁问题
总的来说,智能指针是一个RAII类模板,用于动态分配内存,其设计思想是将基本类型指针封装为(模板)类对象指针,并在离开作用域时调用析构函数,使用delete删除指针所执行的内存空间。
unique_ptr
:独占式指针,与所指对象的内存绑定紧密,禁止其他智能指针与其他共享同一个对象。也就是同一时间只能有一个智能指针可以指向该对象
独占的意思是不可以复制(拷贝构造和拷贝复制),但是我们可以利用std::move将其转移给其他unique_ptr(可以移动构造和移动赋值)。一旦转移,这个所有权就会失去,除非被显示归还
从实现上来讲,unique_ptr是一个删除了拷贝构造函数,保留了移动构造函数的指针类型。可以使用右值对unique_ptr进行构造
shared_ptr
:- 实现了共享式拥有的概念,即多个智能指针可以指向相同的对象,该对象以及相关资源会在其所指对象不再使用之后,自动释放与对象相关的资源
它是使用计数机制来表明资源被几个指针共享
可以通过成员函数 use_count() 来查看资源的所有者个数,除了可以通过 new 来构造,还可以通过传⼊auto_ptr,unique_ptr,weak_ptr 来构造。当我们调⽤ release() 时,当前指针会释放资源所有权,计数减⼀。当计数等于 0时,资源会被释放。
weak_ptr
,解决shared_ptr相互引用的问题,两个指针的引用计数永远不会下降为0,从而导致死锁问题。而weak_ptr是对对象的一种弱引用,可以绑定到shared_ptr,但不会增加对象的引用计数。weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能智能,因为它没有普通指针的行为,没有重置*和→。它得最大作用是协助shared_ptr工作,像是旁观者那样观测资源的使用情况
weak_ptr是一种不控制对象生命周期的智能指针,它指向一个shared_ptr管理的对象。进行该对象的内存管理的是那个强引用的shared_ptr
weak_ptr只是提供了对管理对象的一个访问手段。weak_ptr设计的目的是为了配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它只可以从一个 shared_ptr 或另⼀个 weak_ptr 对象构造,,它的构造和析构不会引起引用计数的增加或者减少