为什么在析构函数可以不显式调用构造函数?

时间:2017-07-17 10:40:51

标签: c++ constructor destructor placement-new explicit-destructor-call

在下面的C ++代码中,我可以显式调用析构函数而不是构造函数。这是为什么? ctor不会明确地将更多表达统一与dtor案件联系起来?

class X { };

int main() {
  X* x = (X*)::operator new(sizeof(X));
  new (x) X;  // option #1: OK
  x->X();     // option #2: ERROR

  x->~X();
  ::operator delete(x);
}

3 个答案:

答案 0 :(得分:37)

因为在构造函数启动之前,该地址没有X类型的对象。因此,将x解除引用为X类型或访问它的成员/方法将是未定义行为。

因此x->X();(假设语法)和x->~X()之间的主要区别在于,在第二种情况下,您有一个对象,您可以在其上调用(特殊)成员(如析构函数),而在第一种情况,没有对象,您可以在其上调用方法(甚至是特殊方法 - 构造函数)。

你可能会争辩说这条规则可能有例外,但最终会出现语法偏好问题,两种情况都存在不一致之处。使用当前语法,对构造函数的调用看起来不像是对构造函数的调用,在您提出的语法中,析构函数调用将具有对称性,但规则中的不一致性决定了何时可以取消引用/访问对象的方法。实际上,必须有一个异常允许在一个不是对象的东西上调用方法。然后你必须在标准的字母中严格定义一些不是对象的东西

答案 1 :(得分:9)

这是鸡蛋问题的变种。

您可以显式调用析构函数,就好像它们是成员函数一样,因为对象的实例已经存在。

你不能对构造函数做同样的事情,因为你要调用它的实例需要存在,并由构造函数完全初始化。

唯一的例外是当您为对象分配了内存但尚未初始化实例时(即实例的内存已存在,但尚未初始化为实际实例)。因此,您需要调用构造函数。这是放置new的情况,您在"选项1"下显示的语法;评论,很有用。但是,这不是您在实例上执行的成员调用,因为该实例在进行该调用之前不可用。

答案 2 :(得分:-1)

您可以使用新的展示位置在任意位置构建对象。

new()调用可以用参数覆盖;放置构造函数采用void*或指向类型的指针。 new()函数总是带一个size_t参数,即sizeof()类型;这通常仅由全局新函数

使用

在编写内存池时使用了placement构造函数和explicate析构函数。

例如(来自记忆!)

class MyClass
{
    public:
       inline new(size_t size, MyClass *ptr) { return ptr; };
};

像这样使用

{
    MyClass *x = ...;
    MyClass *y = new (x) MyClass(construct parameters);
    x->~MyClass();
}

编辑纠正@ Ben-Voigt指出的错误