什么时候是一个完全“创造”的对象?

时间:2012-08-23 08:17:14

标签: c++ memory exception-handling constructor

假设我们有一些带有构造函数的类:

class MyClass
{
public:
    MyClass()
    {
    //our code goes here
    throw "OMG";//well, some code that throws an exception
    }
};

现在,当发生异常时,正在执行堆栈展开。我也知道如果从构造函数抛出异常,相应对象的析构函数将被调用,因为该对象从未在第一时间完全“创建”。

我有点困惑。对我而言,暗示只有在构造函数完成时才会将对象视为“创建”。但显然,所有内存都是在调用构造函数之前(或之后)的某个地方分配的,因为我们可以在构造函数中操作对象的成员。

那么在内存中创建的对象到底是什么时候,导致异常的对象的内存会发生什么?

3 个答案:

答案 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