📢前言
智能指针是行为类似于指针的类对象,单这种对象还有其他功能。本文介绍三个可帮助管理动态内存分配的智能指针类。先来看看需要哪些功能以及这些功能是如何实现的。请看下面的函数:
void remodel(std::string & str) { std::string * ps = new std::string(str); ... str = ps; return; }
您可能发现了其中的缺陷。每当调用时,该函数都分配堆中的内存,单从不回收,从而导致内存泄漏。您可能也知道解决之道——只要别忘了在return语句前添加下面的语句,以释放分配的内存即可:
delete ps;
然而,但凡涉及“别忘了”的解决方法,很少是最佳的。因为您有时可能忘了,有时可能记住了,但可能在不经意间深处或注释掉了这些代码。即使确实没有忘记,也可能有问题。请看下面的变体:
void remodel(std::string & str) { std::string * ps = new std::string(str); ... if (weird_thing()) throw exception(); str = *ps; delete ps; return; }
当出现异常时,delete将不被执行,因此也将导致内存泄漏。
如果ps有一个析构函数,该析构函数将在ps过期时释放它指向的内存,那么问题就解决了。因此,ps的问题在于,它只是一个常规指针,不是有析构函数的类对象。如果它是对象,则可以在对象过期时,让它的析构函数删除指向的内存。这正式auto_ptr、unique_ptr和shared_ptr背后的思想。模板shared_ptr允许多个指针指向同一个对象,unique_ptr独占一个对象。定义在meory头文件中。模板auto_ptr是C++98提供的解决方案,C++11已将其摒弃。然而,虽然auto_ptr被摒弃,单它已经使用了多年;同时,如果您的编译器不支持其他两中解决方法,auto_ptr将是唯一的选择方案。
总结:为什么使用智能指针?
new申请动态内存,delete释放动态内存,注意有new必须要有相应的delete删除内存,不然会产生内存泄漏问题。为了解决这种内存泄漏问题,标准库包含两种智能指针(unique_ptr和shared_ptr),其可以自动释放内存。
✨动态内存与智能指针
这三个只能指针模板(auto_ptr/unique_ptr和shared_ptr)都定义了类似指针的对象,可以将new或make_shared获得(直接或间接)的地址赋给这种对像。当只能指针过期时,其析构函数将使用delete来释放内存。因此,如果将new或make_shared返回的地址赋给这些对像,将无需记住稍候释放这些内存:在智能指针过期时,这些内存将自动被释放。
💫智能指针—shared_ptr
定义shared_ptr,定义和其它的模板类似,需要使用<>,默认初始化时会产生空指针。
shared_ptr<int>p1; //p1为指针,指向string类型 shared_ptr<vector<int>>p2;//p2为指针,指向int的vector
一、分配和使用动态内存的方法:
1)使用new返回地址
std::shared_ptr<Test> p(new Test);
很显然这段代码会引起一个内存分配,但实际上是有两次内存分配。条款19解释了每个std::shared_ptr会指向一个控制块,这个控制块除了其他一些东西,包含了所指对象的引用计数。控制块的内存分配是在std::shared_ptr的构造函数中进行的。这样直接用new需要为Widget来分配一次内存,还要为控制块再分配一次内存。
2)使用std::make_shared来代替new返回地址
std::shared_ptr<Test> p = std::make_shared<Test>();
这样一次内存分配就足够了。那是因为std::make_shared会分配一块独立的内存既保存Widget对象又保存控制块。 这个优化减小了程序的静态尺寸,因为代码只包含一次内存分配的调用,同时增加了代码执行速度,因为只有一次内存分配。
总结:make_shared要优于使用new,make_shared可以一次将需要内存分配好,返回一个shared_ptr指针。在memory中定义,是最安全的分配和使用动态内存的方法。
注:要创建智能指针对象,必须包含头文件memory,该文件模板定义。然后使用通常的模板语法来实例化所需类型的指针。
此外,智能指针有一个get函数,可以得到shared_ptr指向对象的内置指针。
std::shared_ptr<int>p(new int(2)); int *q=p.get();//q为一个内置指针,指向和p同一个对象,注意不要delete q
💥智能指针—unique_ptr
和shared_ptr不同,unique_ptr拥有它所有的唯一对象,这样就保证unique_ptr被销毁时,其对象也会被销毁。
只能使用new进行直接初始化,不支持普通拷贝和赋值。
std::unique_ptr<int>p1(std::make_shared<int>(2));//直接初始化 std::unique_ptr<int>p2; p2=p1;//错误,不能同时指向一个对象
但可以所有权转移,使用reset或release。
unique_ptr<int>p1(new int(2)); unique_ptr<int>p2(p1.release());//release会将p1置为空,就是切断p1和它对象的联系 unique_ptr<int>p3(new int(1)); p2.reset(p3.release());//将p3置空并转权给p2;
戳戳小手帮忙点个免费的赞和关注吧,嘿嘿。 |