堆栈展开动态创建的对象,该对象的构造函数也作用于堆
Stack unwinding dynamically created object whose constructor acts also on heap
当类的构造函数在堆上分配内存时,例如
class bla
{
private:
double *data;
int size;
public:
bla(int s)
{
size = s;
data = new double [size];
}
~bla()
{
delete[] data;
}
}
我有一个功能,例如
void f(bool huge)
{
bla *ptr;
if (huge)
ptr = new bla(1e10);
else
ptr = new bla(1e2);
//...
delete ptr;
}
如果ptr = new bla(1e10)
的分配成功(这意味着分配了data
和size
),但没有构造函数->因为1e10太大而抛出异常,会发生什么?我没有data = new double [size]
的内存泄漏,但堆上仍然存在double *data
和int size
的内存泄漏吗?还是通过堆叠展开来清除它们?
我应该这样写得更好吗?:
void f(bool huge)
{
bla *ptr = 0;
try { ptr = new bla(1e10); }
catch (...) { delete ptr; throw; }
}
和
class bla
{
private:
double *data = 0;
// ... to not have an delete[] on a non-0 pointer
}
编辑:
一个更详细的例子来说明模板pedefs anwswer:
#include <iostream>
using namespace std;
class bla2
{
private:
double *data;
public:
bla2 ()
{
cout << "inside bla2 constructor, enter to continue";
cin.get();
data = new double [2*256*256*256];
}
~bla2 ()
{
cout << "inside bla2 destructor, enter to continue";
cin.get();
delete[] data;
}
};
class bla
{
private:
bla2 data1;
double data2[2*256*256*256];
double *data3;
public:
bla ()
{
cout << "inside bla constructor, enter to continue";
cin.get();
data3 = new double [8*256*256*256]; // when only 1/4 as much -> then all success
}
~bla ()
{
cout << "inside bla destructor, enter to continue";
cin.get();
delete[] data3;
}
};
void main()
{
bla *a;
cout << "program start, enter to continue";
cin.get();
try { a = new bla; }
catch (...) { cout << "inside catch, enter to continue"; cin.get(); exit(EXIT_FAILURE); }
cout << "success on a, enter to continue";
cin.get();
delete a;
}
在这个例子中,我可以在我的机器(Win7 4GB RAM)上很好地看到关于资源监视器,它是如何首先进入bla2()
,然后进入bla()
的,但由于分配失败,data3
首先调用~bla2()
,然后在catch(...)
中结束(没有~bla()
),内存处于基线,就像程序启动时一样。
当我将data3元素的数量设置为只有1/4时,那么所有的元素都会成功,构造函数和析构函数的调用顺序都是预期的。
在C++中,如果new
创建的对象的构造函数抛出异常,则该语言保证为该对象分配的内存将被释放。这意味着您不应该捕获异常并释放内存,因为内存已经被释放,并且您将得到未定义的行为。
如果构造函数抛出异常,则不会调用对象的析构函数。在您的情况下,这不是问题——如果内部分配失败,为数组保留的内存将被清除,异常将向外传播。你不需要做任何花哨的事。但是,如果您有多个分配,您可能希望在构造函数中添加异常处理,以捕获任何分配失败并适当地解除分配。
然而,有一个更简单的解决方案:不要使用new[]
和delete[]
来分配阵列。相反,使用std::vector
,它处理自己的所有分配和解除分配,不需要你照顾孩子。:-)
希望这能有所帮助!
- 类中的 Arduino 对象构造函数设置垃圾值
- 编译错误:临时对象构造函数中缺少参数
- 双指针在使用 new 时不调用对象构造函数
- 以支持继承的方式将自身shared_ptr添加到对象构造函数中的向量中
- 在创建对象向量时,不为每个对象唯一调用默认对象构造函数
- GCC __attribute__((constructor)) 在对象构造函数之前调用
- 自定义对象构造函数在循环外部循环
- 从全局对象构造函数停止监视器计时器
- Arduino 上的 Sketch 停止在对象构造函数中执行
- 通过在引用线程对象来传递取消引用的“this”指针来在函数对象构造函数中创建线程是好是坏
- 为什么当对象构造函数投入新表达式时,为什么不调用DealLocation函数
- 临时结构对象构造函数奇数调用
- 未显式引用对象的全局对象构造函数在最终二进制文件 - LD 中被丢弃
- 为什么 Clang++ 不在另一个静态库中运行全局对象构造函数?
- 在未加载上下文的情况下在对象构造函数中使用OpenGL函数
- 为什么我们需要一个用户提供的const对象构造函数
- 对象构造函数的C++数组
- 将子结构值设置为对象构造函数中安全的纯虚拟函数返回的值
- C等价于新对象(构造函数)
- C++:直接在参数列表中使用数组文字的对象构造函数