How does C++ automatically call destructor?
Asked Answered
A

1

6

In C++, we can manage resources by objects, i.e. acquiring resource in Ctor, and releasing it in Dtor (RAII). This relies on C++'s automatic destructor invocation. But how is this done under the hood? For example, how C++ know to call Dtor for c1 but not c2. (I know this must have been answered before, but all of my searches ended in topics explaining how to use RAII). Thanks!

class Cat;
Cat c1;
Cat* c2 = new Cat();

Edit: I know I need to call delete for c2. I just don't understand how Dtor is called when c1 goes out of scope.

Autotoxin answered 29/8, 2017 at 13:9 Comment(17)
GCC is free software, Clang is open-source. Go and find out.Goldiegoldilocks
You got it backwards, in your example c1's destructor will be called (when it goes out of scope), not *c2's. That's why new is seldom used in modern c++ (search for "c++ smart pointer" in your search engine of choice).Invalidism
It's done because the C++ standard says it must be done. And how it's done is by having your C++ compiler generate compiled code that complies to the C++ standard.Strangulate
The compiler adds it into the assembly.Streetlight
@Invalidism oops, I meant the other way. corrected.Autotoxin
@rzmn Use std::unique_ptr<Cat> to have the destructor automatically called.Insomuch
https://mcmap.net/q/150371/-in-c-do-braces-act-as-a-stack-frame/1460794Intramolecular
The destructor is automatically called when the scope of a variable ends...Guayaquil
The destructor is called for c2 too, just not the Cat destructor but the Cat* destructor, which is trivial.Lumpen
Possible duplicate of Is a destructor called when an object goes out of scope?Quarterback
@Rick so Dtor is called for EVERY object/pointer/(what else?) that resides on stack?Autotoxin
Pointer don't have destructors. Neither do built in types. All the rest (every custom struct or class) do and does get called. Probably POD's don't either. In general everything is destroyed once it goes out of scope. Destroying a pointer however does not call the destructor of what it points to.Goodhen
You forgot to delete your object. You should always call delete when you are finished with the object.Richelle
@rzmn> what Rick meant is the pointer c2 is disposed of. Not the pointed object.Invalidism
@Goodhen conceptually, they do. Its just they are defined to be trivial. It's much easier to define it that way so that you can say things like "template <typename T> struct Thing { T member; } has an implicitly declared destructor, which is trivial if T's destructor is trivial ..." Rather than "... which is trivial if T's destructor is trivial, or T is a pointer, or arithmetic, or array of trivially destructible, or ... type"Junejuneau
@Junejuneau I don't think they do though. You cannot call an int's destructor. You can however call it's constructor. Excample codeGoodhen
@Goodhen Calling ~int()Junejuneau
P
13

Take a look at compiler explorer. I've linked a buildable version of your example. Just in case the link is not permanent, I've copied the code at the end if this answer.

For the Cat c1; line (in light red) you will see that there are three corresponding blocks in the asm, same colour.

lea rax, [rbp-28]
mov rdi, rax
call Cat::Cat()

This matches the construction of the object on the stack.

Next there is

lea rax, [rbp-28]
mov rdi, rax
call Cat::~Cat()

This is the normal return path, calling the destructor automatically.

Finally there is

lea rax, [rbp-28]
mov rdi, rax
call Cat::~Cat()
mov rax, rbx
mov rdi, rax
call _Unwind_Resume

This is the path taken if an exception is thrown (e.g., by new). It automatically calls the destructor and then continues the exception.

For the sake of completeness, here is the C++ source code:

    class Cat
    {
    public:
        Cat() : meow() {}
        ~Cat() {}
    private:
        int meow;
    };

    void foo()
    {
        Cat c1;
        Cat* c2 = new Cat();
    }

    int main()
    {
        foo();    
    }
Paeon answered 29/8, 2017 at 13:28 Comment(1)
+1 for compiler explorer. In particular since you can easily add more complex control flow to the code and see how the generated destructor calls move around.Tricyclic

© 2022 - 2024 — McMap. All rights reserved.