动态分配对象时,对象存储在heap上,若不及时或者忘了delete对象指针,会造成内存泄露
即便最后没有忘记delete对象指针,在函数运行到delete语句之前,可能会遇到以下状况使得delete语句不被执行:
为了防止资源泄露,主要有两点要注意:
常用的资源管理对象有auto_ptr、shared_ptr
其中auto_ptr允许资源剥夺,即同一时刻只有一个auto_ptr指向资源,那么就不符合传统的copy理念
class A {...
}A* createA(); //工厂函数,返回一个指向动态创建class A对象的指针void f() {auto_ptr<A> pA1(createA()); //pA1指向class A对象auto_ptr<A> pA2(pA1); //pA2剥夺pA1占有的资源,pA1为null
}
因此,为了实现一般意义上的对象资源拷贝,可以使用shared_ptr来替换auto_ptr
shared_ptr使用引用计数的机制,计数器持续追踪有多少shared_ptr对象指向这份资源,当计数器=0的时候才会释放资源,每一次拷贝动作,就是计数器+1
class A {...
}A* createA(); //工厂函数,返回一个指向动态创建class A对象的指针void f() {shared_ptr<A> pA1(createA()); //pA1指向class A对象shared_ptr<A> pA2(pA1); //pA2与pA1指向同一个class A对象
}
注意,auto_ptr和shared_ptr在析构时都是delete而不是delete[],因此如下形式虽然能通过编译,但是与原本目的并不相同
auto_ptr<string> pStr(new string[10]);
有时候,一些资源并不是存储在heap上的,也就不能使用auto_ptr或者shared_ptr来管理资源了,这时候需要自定义一个资源管理class
自定义的资源管理class需要遵循:调用资源管理class的构造函数时,应该传入需要管理的资源(如指向资源的指针),在调用资源管理class的析构函数时,确保管理的资源被正确释放。这也就是**{资源在构造期间获得,在析构期间释放}——RAII**的解释
那么当一个资源管理class的对象被复制时,一般有如下几种策略:
资源管理class除了具备RAII的性质之外,最好对外提供能够访问原始资源的手段:提供一种方法能够将RAII class对象转换为其所含有的原始资源
这里的手段主要有(以shared_ptr为例):
显式转换:shared_ptr提供一个成员函数get(),来执行显示转换
shared_ptr<A> pA(createA());
A* pAOri = pA.get(); //显示转换为原始资源的指针
隐式转换:shared_ptr重载了operator->和operator*
int a = pA->a; //a是class A的成员变量
使用new会做两件事:
同样,使用delete也会做两件事:
而使用delete的问题在于:在即将被释放的内存中,有多少个对象,这决定了调用多少个析构函数
当使用delete[]时,delete认为将要操作的指针指向一个数组,否则delete认为将要操作的指针指向单个对象
newed对象,看时态,就是在独立语句(该语句只完成这一功能)中使用智能指针指向new出来的对象
为什么要用独立语句呢,因为:
void func1(shared_ptr<A> pA, int b);
int func2();//传入实参
func1(shared_ptr<A>(new A), func2());
这里其实有三件事,按照理想顺序应该是:
但是,C++编译器并不一定会按照这个顺序完成这三件事,实际的顺序很可能是:
如果在这个过程中,在第2步出现了异常,那么new出来的class A对象没有置入智能指针,并且没有delete,就会造成内存泄漏
本文发布于:2024-01-29 08:55:40,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170648974514141.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |