Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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
like image 339
PoweredByRice Avatar asked Aug 22 '18 20:08

PoweredByRice


People also ask

Why are destructors called?

A destructor is called for a class object when that object passes out of scope or is explicitly deleted.

Why destructor is used when delete is there?

When delete is used to deallocate memory for a C++ class object, the object's destructor is called before the object's memory is deallocated (if the object has a destructor). If the operand to the delete operator is a modifiable l-value, its value is undefined after the object is deleted.

Why is my destructor being called twice?

The signal emission most probably creates a copy of the object (using default copy constructor - so pointers in both object point to the same thing!), so the destructor is called twice, once for your filtmp and second time for the copy. Up to this point signal is not connected to anywhere.

Is the destructor automatically called?

A destructor is a member function that is invoked automatically when the object goes out of scope or is explicitly destroyed by a call to delete . A destructor has the same name as the class, preceded by a tilde ( ~ ).


3 Answers

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.

like image 103
Barry Avatar answered Sep 24 '22 06:09

Barry


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.

like image 34
Oliv Avatar answered Sep 24 '22 06:09

Oliv


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.

like image 32
eerorika Avatar answered Sep 20 '22 06:09

eerorika