Search code examples
c++c++17language-lawyerdestructortemporary

Why destructor needs to be accessible even when it is not called?


Having class X, the following object initialization:

new (ptr) X(X());

requires an accessible destructor even since C++17. Why is that, when the object is initialized by the default constructor directly in the storage pointed to by ptr, so no temporary should be involved?

Example code:

struct X {
  X() { }
  X(const X&) = delete;
  X(X&&) = delete;
  ~X() = delete;  // or, e.g, private
};

void test(void* ptr) {
  new (ptr) X(X());  // error: attempt to use a deleted function
}

Demo: https://godbolt.org/z/Khac1z8r3

UPDATE

This is a similar question: Why is public destructor necessary for mandatory RVO in C++?. But my case is different, since in my code, the problem of potential destructor calls due to exceptions does not apply (or, at least, I can't see it there).


Solution

  • The compilers are not behaving correctly (assuming C++17 or later).

    In your code the destructor of X is not explicitly invoked, it is not implicitly invoked according to [class.dtor]/14 sentence 1 or sentence 3 and it is also not potentially invoked according to [class.dtor]/14 sentence 6.

    In particular there is no implicit invocation of the destructor to destroy a temporary object, because none exists. The new-expression direct-initializes the object it creates from the initializer of the new expression. The single parenthesized argument in the initializer is a prvalue of type X and according to [dcl.init.general]/16.6.1 this means the destination object is immediately initialized from the initializer of the prvalue argument. No temporary materialization conversion happens.

    Therefore, it ought to not matter that the destructor is deleted.

    For Clang this seems to have been reported already a while ago, see bug report, but there hasn't been any activity on the report.