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

Why can't constructors be explicitly called while destructors can?

在下面的 C++ 代码中,我可以显式调用析构函数而不是构造函数。这是为什么?不会显式 ctor 调用更多 expressiveunified 与 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);
}

因为在构造函数启动之前,那个地址没有X类型的对象。因此,将 x 取消引用为 X 类型或访问它的 members/methods 将是未定义的行为。

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

您可能会争辩说此规则可能存在例外情况,但这最终将是语法偏好的问题,在这两种情况下您都存在不一致之处。使用当前语法,对构造函数的调用看起来不像是对构造函数的调用,在您提出的语法中,析构函数调用将具有对称性,但在管理何时可以 dereference/access 对象方法的规则中存在不一致.实际上必须有一个例外允许在还不是对象的东西上调用方法。那么你将不得不在标准的字母中严格定义还不是对象的东西

这是先有鸡还是先有蛋的问题的变体。

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

您不能对构造函数执行相同的操作,因为您调用它的实例需要存在,并且需要由构造函数完全初始化。

唯一的例外是当你已经为对象分配了内存,但还没有初始化实例(即实例的内存在那里,但还没有被初始化成为一个实际的实例)。因此,您需要调用构造函数。在这种情况下,放置 new(您在 "option 1" 注释下显示的语法)很有用。但是,这不是您对实例执行的成员调用,因为在进行该调用之前该实例不可用。

您可以使用新的放置在任意位置构造对象。

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

写内存池的时候会用到placement constructor和explicate destructor

例如(凭记忆!)

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 指出的错误