当前位置: 首页 > 科技观察

掌握C++智能指针的使用

时间:2023-03-16 22:10:22 科技观察

RAII和引用计数了解Objective-C/Swift的程序员应该知道引用计数的概念。引用计数产生这种计数是为了防止内存泄漏。基本思想是对动态分配的对象进行引用计数。每当添加对同一对象的引用时,被引用对象的引用计数就会增加一次。每删除一个引用,引用计数就会减一。当一个对象的引用计数减为零时,指向的堆内存被自动删除。在传统的C++中,“记住”手动释放资源并不总是最佳实践。因为我们很可能忘记释放资源而造成泄漏。所以通常的做法是,对于一个对象,我们在构造函数中申请空间,在析构函数中释放空间(离开作用域时调用),也就是我们常说的RAII资源获取和初始化技术。凡事都有例外。我们总是需要在空闲存储上分配对象。在传统的C++中,我们不得不使用new和delete来“记住”释放资源。C++11引入了智能指针的概念,利用引用计数的思想,让程序员不再需要关心手动释放内存。这些智能指针包括std::shared_ptrstd::unique_ptrstd::weak_ptr,使用它们需要包含头文件。注意:引用计数不是垃圾回收。引用计数可以尽快回收不再使用的对象,同时不会造成回收过程中的长时间等待,并且可以清楚地表明资源的生命周期。std::shared_ptrstd::shared_ptr是一个智能指针,可以记录有多少个shared_ptr指向一个对象,从而无需显式调用delete,当引用计数变为零时该对象将被自动删除。但这还不够,因为使用std::shared_ptr还是需要用new来调用,这使得代码有些不对称。std::make_shared可用于消除显式使用new,因此std::make_shared会分配并创建传入参数中的对象,并返回一个该对象类型的std::shared_ptr指针。例如:#include#includevoidfoo(std::shared_ptri){(*i)++;}intmain(){//autopointer=newint(10);//不合法,nodirectassignment//构造astd::shared_ptrautopointer=std::make_shared(10);foo(pointer);std::cout<<*pointer<(10);autopointerpointer2=pointer;//引用计数+1autopointerpointer3=pointer;//引用计数+1int*p=pointer.get();//这个不会增加引用计数std::cout<<"pointer.use_count()="<p1(std::make_unique());//p1不为空,输出if(p1)p1->foo();{std::unique_ptrp2(std::move(p1));//p2不为空,输出f(*p2);//p2不为空,输出if(p2)p2->foo();//p1为空,不输出if(p1)p1->foo();p1=std::move(p2);//p2为空,无输出if(p2)p2->foo();std::cout<<"p2isdestroyed"<foo();//Foo的实例离开作用域时会被销毁资源无法释放的问题。看下面的例子:structA;structB;structA{std::shared_ptrpointer;~A(){std::cout<<"Aisdestroyed"<pointer;~B(){std::cout<<"Bisdestroyed"<();autob=std::make_shared();a->pointer=b;b->pointer=a;}运行结果是A和B都不会被销毁,这是因为a里面的指针和b同时引用了a,b,使得a,b的引用计数变为2,离开作用域时,a,b的智能指针被销毁,但只能导致该区域的引用计数减1.这样a和b对象指向的内存区域的引用计数就不为0,外部就没有办法找到这块区域,也会造成内存泄漏,如图1所示:图1中的这个问题是使用了弱引用指针std::weak_ptr,std::weak_ptr是弱引用(相比之下,std::shared_ptr是强引用)。弱引用不会导致引用计数增加。当使用弱引用时,最终的释放过程如图2所示:图2上图中最后一步只剩下B,B没有任何智能指针指向它。因此,这个内存资源也会被释放。std::weak_ptr没有*运算符和->运算符,因此它不能对资源进行操作。它的唯一功能是检查std::shared_ptr是否存在。它的expire()方法可以在资源未释放时使用。将返回false,否则返回true。综上所述,智能指针技术并不新鲜。它是许多语言的通用技术。现代C++引入了这种技术,在一定程度上杜绝了new/delete的滥用,是一种更加成熟的编程范式。.