《深入理解C++11》笔记-智能指针unique_ptr、shared_ptr、weak_ptr

本篇介绍C++11中新增的智能指针:unique_ptr、shared_ptr、weak_ptr。使用智能指针可以免于我们去主动管理内存,智能指针会自动释放内存:

来源:《深入理解C++11》笔记-智能指针unique_ptr、shared_ptr、weak_ptr_unique_ptr.next_WizardtoH的博客-CSDN博客

C++ 智能指针(shared_ptr/weak_ptr)源码分析___gnu_cxx::_s_atomic_ithiker的博客-CSDN博客

一般的智能指针都定义为一个模板类,它的类型由被管理的对象类型初始化,内部包含了指向该对象的指针以及指向辅助生命周期管理的管理对象的指针。

C++11中unique_ptr, shared_ptr, weak_ptr的特点如下:

  • unique_ptr独享被管理对象,同一时刻只能有一个unique_ptr拥有对象的所有权,当其被赋值时对象的所有权也发生转移,当其被销毁时被管理对象也自动被销毁
  • shared_ptr共享被管理对象,同一时刻可以有多个shared_ptr拥有对象的所有权,当最后一个shared_ptr对象销毁时,被管理对象自动销毁
  • weak_ptr不拥有对象的所有权,但是它可以判断对象是否存在和返回指向对象的shared_ptr类型指针;它的用途之一是解决多个对象内部含有shared_ptr循环指向,导致对象无法释放的问题

C++弱引用智能指针weak_ptr的用处_weak 智能指针_li27z的博客-CSDN博客

weak_ptr也是一个引用计数型智能指针,但是它不增加对象的引用计数,即弱引用。与之相对,shared_ptr是强引用,只要有一个指向对象的shared_ptr存在,该对象就不会析构,直到指向对象的最后一个shared_ptr析构或reset()时才会被销毁。

详细分析智能指针shared_ptr存在的循环引用缺陷,以及通过weak_ptr来解决_weak怎么解决share的互相引用问题__来信的博客-CSDN博客

 详细分析智能指针shared_ptr存在的循环引用缺陷,以及通过weak_ptr来解决

5. 智能指针使用注意事项
https://www.cnblogs.com/ChinaHook/p/7684268.html

5.1 shared_ptr

a.避免一个原始指针初始化多个shared_ptr。

b.不要在参数实参中创建shared_ptr。

c.避免循环使用,循环使用可能导致内存泄漏

d.通过shared_from_this()返回this指针。不要将this指针作为shared_ptr返回出来,因为this指针本质是一个裸指针,这样可能导致重复析构。

e.函数不要返回临时变量智能指针的引用或右值引用(移动构造)

f.C++11创建shared_ptr类型的数组,需要指定删除器,但unique_ptr不用指定;C++20则支持直接创建智能指针的数组

shared_ptr<int> ps(new int[10], [](int *p) {delete[] p;}); //lambda
ps[0] = 0;//error
 
shared_ptr<int []> ptr2(new int[10]); //error
unique_ptr<int []> ptr(new int[10]);  //ok
ptr[1] = 10;//ok
 
//智能指针创建数组模板
template<typename T>
shared_ptr<T> make_shared_array(size_t size) {
    return shared_ptr<T>(new T[size], default_delete<T[]>());
}
// 使用make_shared_array,创建指向数组的
shared_ptr shared_ptr<int> p = make_shared_array<int>(10);//ok
p[0] = 0;//error
pia.get()[0] = 0; //ok


5.2 unique_ptr

unique_ptr<int, void(*)(int *)> ptr2(new int(1), [&](int *p){delete p;}); //error
unique_ptr<int, std::function<void(int*)>> ptr2(new int(1), [&](int *p){delete p;}); //ok
5.3 weak_ptr

弱引用智能指针weak_ptr用来监视shared_ptr,不会使引用技术加1,也不管理shared_ptr内部的指针,主要是监视shared_ptr的生命周期。weak_ptr不共享指针,不能操作资源,它的构造和析构都不会改变引用计数。

5.4 std::enable_shared_from_this类

sharerd_ptr不能直接返回this指针(double free类似5.1 a),需要通过派生std::enable_shared_from_this类,并通过其方法shared_from_this来返回智能指针,因为std::enable_shared_from_this类中有一个weak_ptr,这个weak_ptr用来观测this指针,调用shared_from_this方法时,调用了内部的weak_ptr的lock()方法,将所观测的sharerd_ptr返回。

需要注意的是,获取自身智能指针的函数仅在share_ptr<T>的构造函数调用之后才能使用,因为enable_shared_from_this内部的weak_ptr只有通过shared_ptr才能构造。

5.5 循环引用

shared_ptr的循环引用可能导致内存泄漏,通过weak_ptr可以解决这个问题,将A或者B任意一个成员变量改为weak_ptr即可。

shared_ptr<B> bptr;
weak_ptr<A> aptr;
这样在对B成员赋值时,即bp->aptr = ap,由于aptr是weak_ptr,并不会增加引用计数,所以ap的计数仍然是1,在离开作用域之后,ap的引用计数会减为0,A指针会被析构,析构之后,其内部的bptr引用计数会减1,然后离开作用域之后,bp引用计数从1减为0,B对象也被析构,所以不会发生内存泄漏。

5.6 通过智能指针管理第三方库分配的内存
https://www.cnblogs.com/fortunely/p/15815741.html

如何解决由于忘记赋值导致指针提前释放的问题?
答:可以用一个宏来解决这个问题,通过宏来强制创建一个临时智能指针。代码如:
 
// OK
#define GUARD(p) std::shared_ptr<void> p##p(p, [](void* p) { GetHandler()->Release(p); })
 
void* p = GetHandler()->Create();
GUARD(p); // 安全:会在当前作用域下,创建名为pp的shared_ptr<void>
当然,如果只希望用独占性的管理第三方库的资源,可以用unique_ptr。
 
// OK
#define GUARD(p) std::unique_ptr<void, void(*)(int*)> p##p(p, [](void* p) { GetHandler()->Release(p); })
小结:
1)使用宏定义方式的优势:即使忘记对智能指针赋值,也能正常运行,安全又方便。
2)使用GUARD这种智能指针管理第三方库的方式,其本质是智能指针,能在各种场景下正确释放内存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值