假设我们有一些带有构造函数的类:
class MyClass
{
public:
MyClass()
{
//our code goes here
throw "OMG";//well, some code that throws an exception
}
};
现在,当发生异常时,正在执行堆栈展开。我也知道如果从构造函数抛出异常,相应对象的析构函数将不被调用,因为该对象从未在第一时间完全“创建”。
我有点困惑。对我而言,暗示只有在构造函数完成时才会将对象视为“创建”。但显然,所有内存都是在调用构造函数之前(或在之后)的某个地方分配的,因为我们可以在构造函数中操作对象的成员。
那么在内存中创建的对象到底是什么时候,导致异常的对象的内存会发生什么?
答案 0 :(得分:2)
内存分配和对象构造是C ++中的两个独立的东西。编译器只是确保当它们一起被调用时(常规 - 即非放置 - new
运算符的情况)并且构造失败,则恢复分配。
此外,当类具有子对象(基类和/或字段)时,编译器以固定顺序调用它们的构造函数并确保比其中一个抛出时,已经构造的子对象被处理掉正确地(即,他们的析构函数被称为)。
答案 1 :(得分:2)
内存在构造函数体之前分配。
如果构造函数失败,则自动分配的内存将被释放。
“自动分配”的重音非常重要 - 如果您在构造函数中动态分配了内存并且构造函数失败(例如,您可能在new
之前使用过throw "OMG"
) ,这个记忆会泄漏。
那是因为 - 你已经分配了这个内存,你需要释放它。
你是对的,没有调用析构函数,但析构函数不是释放内存的那个,为类的 auto 成员分配。
它(基本上)用于释放内存,由用户分配 (在构造函数或其他地方)。
换句话说,为对象分配内存与对象的构造不同。
另一个例子 - 如果你动态创建一个对象,比如:
MyObj* = new MyObj;
这将:
operator new
MyObj
看,两者都不一样。
答案 2 :(得分:1)
释放对象的内存,但不调用析构函数(因此,如果未正确处理构造函数中的异常,则不会释放在构造函数中创建的动态分配的指针)。在C ++ 11中,规范指出,当且仅当一个构造函数完全完成时才会调用析构函数(因为构造函数可以引用另一个构造函数)。
示例(未释放由new int()分配的内存):
struct Broken {
int * i;
Broken () {
i = new int {5};
OperationCausingException ();
}
~Broken {
delete i;
}
}
try {
Broken * b = new Broken {};
} catch (...) {
}
// memory leak: *b is freed, but b->i still exists