运维开发网

SmartPointer智能指针详细介绍

运维开发网 https://www.qedev.com 2022-10-23 19:12 出处:网络
<p这篇文章主要为大家详细介绍了C++SmartPointer智能指针,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

<p这篇文章主要为大家详细介绍了C++SmartPointer智能指针,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助


一、为啥使用智能指针呢标准库中的智能指针:std::auto_ptr --single ownership (C++98中出现,缺陷较多,被摒弃)std::unique_ptr --single ownership (C++11替代std::auto_ptr,用于单线程)std::shared_ptr --shared ownership (C++11,用于多线程)std::weak_ptr --temp/no ownership (C++11)Introduced in C++ 11Defined in lt;memorygt; header.

先看下面一个栗子。左边是不使用智能指针的情况。foo()函数执行时,其中的E指针会在bar(e)结束时传入bar函数,但当bar函数结束后没有人人为删除E时,就会导致内存泄漏。但是在右边的栗子中,使用了unique_ptr智能指针(单一所有权)来防止内存泄漏。


智能指针主要用于管理堆上分配的内存。它将一个公共指针封装到一个堆栈对象中。当stack对象的生命周期结束时,所请求的内存将在析构函数中释放,从而防止内存泄漏。

auto_ptr智能指针:(C++11出来前只有这种智能指针)当对象拷贝或者赋值后,前面的对象就悬空了。unique_ptr智能指针:防止智能指针拷贝和复制。shared_ptr智能指针:通过引用计数的方式来实现多个shared_ptr对象之间共享资源。weak_ptr智能指针:可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。

注意:每个智能指针都可以增加内存的引用计数。

智能指针分为两类:一种是可以使用多个智能指针管理同一块内存区域,每增加一个智能指针,就会增加1次引用计数,另一类是不能使用多个智能指针管理同一块内存区域,通俗来说,当智能指针2来管理这一块内存时,原先管理这一块内存的智能指针1只能释放对这一块指针的所有权(ownership)。按照这个分类标准,auto_ptrunique_ptrweak_ptr属于后者,shared_ptr属于前者。

在初始化shared_ptr时,不能直接给智能指针赋一个公共指针,因为一个是指针,一个是类。可以通过make_shared函数或构造函数传入一个公共指针。并且可以通过get函数得到一个公共指针。

#include lt;stringgt;#include lt;memorygt;using namespace std;class report{private: string str;public: report(const string s):str(s) //构造方法 { coutlt;lt;"1 report Object has been build!"lt;lt;endl; } ~report() { coutlt;lt;"3 report Object deleted!"lt;lt;endl; } void talk() { coutlt;lt;strlt;lt;endl; }};int main(){ string talk="2 hello,this is a test!"; { auto_ptrlt;reportgt; ptr(new report(talk)); ptr-gt;talk(); } { shared_ptrlt;reportgt; ptr(new report(talk)); ptr-gt;talk(); } { unique_ptrlt;reportgt; ptr(new report(talk)); ptr-gt;talk(); } return 0;}



二、shared_ptr智能指针

Shared_ptr实现了共享所有权的概念,使用ldquo伯爵rdquo控制堆上对象的生命周期。

share_ptr的生命周期:


原理:引用计数在初始化时设置为1,每当被复制或赋值时设置为+1,当被析构时设置为-1,直到引用计数减少到0,然后对象的指针可以被删除。他的构造主要有三种方式:

shared_ptrlt;Objectgt; ptr;shared_ptrlt;Objectgt; ptr(new Object);shared_ptrlt;Objectgt; ptr(new Object, [=](Object *){ //回收资源时调用的函数 });auto ptr = make_sharedlt;Objectgt;(args);第一种空构造,没有指定shared_ptr管理的堆上对象的指针,所以引用计数为0,后期可以通过reset()成员函数来指定其管理的堆上对象的指针,reset()之后引用计数设为1。第二种是比较常见的构造方式,构造函数里面可以放堆上对象的指针,也可以放其他的智能指针(如weak_ptr)。第三种构造方式指定了shared_ptr在析构自己所保存的堆上对象的指针时(即引用计数为0时)所要调用的函数,这说明我们可以自定义特定对象的特定析构方式。同样的,reset()成员函数也可以指定析构时调用的指定函数。第四种方法:较常见,构造shared_ptr的方式(最安全):auto ptr = make_sharedlt;Objectgt;(args);

上面第四种方法使用标准库中的make _ sharedltgt;()模板函数。这个函数调用模板类的构造函数,在堆上实例化一个对象,然后返回保存该对象指针的shared_ptr。参数是这个类构造函数的参数,所以make _ sharedltgt;()就像简单的构造这个类对象。是auto C++11的一个关键字,可以在编译时自动计算变量的类型,这里是shared _ ptrltObjectgt。类型。


shared_ptr的其他成员函数:

use_count()//返回引用计数的个数unique()//返回是否是独占所有权(use_count是否为1)swap()//交换两个shared_ptr对象(即交换所拥有的对象,引用计数也随之交换)reset()//放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少


三、unique_ptr智能指针

注意unique_ptr是单所有权,不能复制。其构建方式如下:


unique_ptr的生命周期:



四、weak_ptr智能指针



五、智能指针怎么解决交叉引用,造成的内存泄漏

结论:创建对象时使用shared_ptr强智能指针指针,其他情况下使用weak_ptr迟滞指针。


5.1 交叉引用的栗子:

当A类中有shared_ptr强类型智能指针指向B类时,B类中也有shared_ptr强类型智能指针指向A类。

主函数执行后,有两个强智能指针指向对象A,对象A的引用计数为2,类B也是这样:

#include lt;iostreamgt;#include lt;memorygt;using namespace std;class B;class A{public: shared_ptrlt;Bgt; _bptr;};class B{public: shared_ptrlt;Agt; _aptr;};int main(){ shared_ptrlt;Agt; aptr(new A()); shared_ptrlt;Bgt; bptr(new B()); aptr-gt;_bptr = bptr; bptr-gt;_aptr = aptr; return 0;}


当main函数的return返回时,对象A的引用计数减少到1(aptr不指向对象A),对象b也是如此,如果引用计数不为0,则无法析构两个对象来释放内存,导致内存泄漏。


5.2 解决方案

将A类和B类中的shared_ptr强智能指针替换为weak_ptr迟滞指针;

class A{public: weak_ptrlt;Bgt; _bptr;};class B{public: weak_ptrlt;Agt; _aptr;};

weak_ptr智障指针,虽然有引用计数,但实际上并不增加计数,只是观察对象的引用计数。所以对象A的引用计数只有1,对象B的引用计数也只有1。



六、智能指针的注意事项避免同一块内存绑定到多个独立创建的shared_ptr上,因此要不使用相同的内置指针初始化(或reset)多个智能指针,不要混合使用智能指针和普通指针,坚持只用智能指针。不delete get() 函数返回的指针,因为这样操作后,shared_ptr并不知道它管理的内存被释放了,会造成shared_ptr重复析构。不使用 get()函数初始化或(reset)另外的智能指针。shared_ptrlt;intgt; p = make_sharelt;intgt; (42);int *q = p.get();{ shared_ptrlt;intgt;(q); } // 程序块结束,q被销毁,指向的内存被释放。int foo = *p; // 出错,p指向的内存已经被q释放,这是用get() 初始化另外的智能指针惹得祸。// 请记住,永远不要用get初始化另外一个智能指针。

在可以使用unique_ptr的情况下,不要使用share_ptr指针(后者需要保证线程安全,所以在赋值器被销毁时开销成本较高)。


总结

本文到此为止。希望能帮到你>    

0

精彩评论

暂无评论...
验证码 换一张
取 消