Why is the destructor called for an object that is not deleted?

C++Language Lawyer

C++ Problem Overview


struct A
{
    ~A() = delete;
};

int main()
{
    new A{};
}

This fails to compile with error message:

> error: use of deleted function 'A::~A()' > new A{};

As I understand I'm not destroying the object so why is it trying to call the destructor?

Compiled with GCC 8.1.0

g++ -std=c++17 -O2

C++ Solutions


Solution 1 - C++

This is gcc bug 57082.


Let's go from the bottom up.

[dcl.fct.def.delete]/2:

> A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.

Clearly, we're not referring to ~A() explicitly. Are we referring to it implicitly? [class.dtor]/12:

> A destructor is invoked implicitly
> > * for a constructed object with static storage duration ([basic.stc.static]) at program termination ([basic.start.term]),
> * for a constructed object with thread storage duration ([basic.stc.thread]) at thread exit,
> * for a constructed object with automatic storage duration ([basic.stc.auto]) when the block in which an object is created exits ([stmt.dcl]),
> * for a constructed temporary object when its lifetime ends ([conv.rval], [class.temporary]).

Or in [expr.new]/20:

> If the new-expression creates an array of objects of class type, the destructor is potentially invoked.

Do we have any of those things? No, there is no object with automatic, static, or thread storage duration here, nor is there a constructed temporary object, nor is our new-expression creating an array. There is only one object here at all, the one A with dynamic storage duration that we're aggregate-initializing.

Since we're neither explicitly nor implicitly referring to ~A(), we can't be tripping over that rule. Hence, gcc bug. Note also that gcc accepts new A; and new A();, which have the same meaning as far as this rule is concerned.

Solution 2 - C++

Probably a gcc bug here.

The standard specifies that the destructor is potentially invoked when the new expression create an array [expr.new]:

>If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function, and the constructor. If the new-expression creates an array of objects of class type, the destructor is potentially invoked.

emphasis mine

gcc applies also this rule when creating a non array, which is implicitly not a standard rule. Thanks to below comments it seems gcc do the exact opposite: when creating a non array, it considers the destructor to be potentialy invoked and when creating an array it just don't check the destructor.

Solution 3 - C++

As far as I can tell, no objects are destroyed in the example, and it happens to compile if the expression is changed to new A;

I think that the example code not compiling is is a bug in GCC. Clang compiles it just fine.


Answer for the newly added language-lawyer tag.

The crucial standard rule is this in [class.dtor]:

> A destructor is invoked implicitly > > ... cases that don't apply involving other storage durations than dynamic ... > > ... A destructor is also invoked implicitly through use of a delete-expression (5.3.5) for a constructed object allocated by a new-expression (5.3.4); the context of the invocation is the delete-expression. [ Note: An array of class type contains several subobjects for each of which the destructor is invoked. — end note ] A destructor can also be invoked explicitly. A destructor is potentially invoked if it is invoked or as specified in 5.3.4, 12.6.2, and 15.1.

5.3.4 is [expr.new] which only specifies

> ... If the new-expression creates an array of objects of class type, the destructor is potentially invoked (12.4).

which doesn't apply.

12.6.2 is [class.base.init] which only specifies

> In a non-delegating constructor, the destructor for each potentially constructed subobject of class type is potentially invoked (12.4).

Which doesn't apply

15.1 is [except.throw] which specifies how an exception object is destroyed, which doesn't apply

Conclusion: None of sections 5.3.4, 12.6.2, and 15.1. contain a rule that applies to this case, and the destructor isn't invoked, nor is there a delete-expression. Therefore the destructor isn't potentially invoked, so it is well formed for the destructor to be deleted.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPoweredByRiceView Question on Stackoverflow
Solution 1 - C++BarryView Answer on Stackoverflow
Solution 2 - C++OlivView Answer on Stackoverflow
Solution 3 - C++eerorikaView Answer on Stackoverflow