1

This code:

#include <iostream>

class Base { };

class Derived : public Base
{
public:
    ~Derived()
    {
        std::cout<< "Derived dtor" << std::endl;
    }
};

int main()
{
    Derived objD;
    objD.~Derived();
    return 0;
}

prints:

Derived dtor // destructor called
Derived dtor // printed by 'return 0'

I don't have idea from where comes the second line.

With this main:

int main()
{
    Derived objD;
    return 0;
}

It prints only one line.

Super Mario
  • 923
  • 10
  • 16
  • 7
    `objD` is on the stack, so its destructor will be called when it goes out of scope, regardless of whether you manually called it before. – Blaze Mar 07 '19 at 13:22
  • 3
    You do not have to - and in fact must not, in this or almost any other situation - call the destructor explicitly. It's already done automatically when exiting the scope in which `objD` is declared. – Useless Mar 07 '19 at 13:22
  • 1
    well... this is how it works. Once you understand c++ you will appreciate and love the fact that destructors are called in that way. You almost never should call the destructor yourself – 463035818_is_not_an_ai Mar 07 '19 at 13:22
  • And so you have UB currently. – Jarod42 Mar 07 '19 at 13:23
  • seems like you could use a [good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – 463035818_is_not_an_ai Mar 07 '19 at 13:23
  • 2
    Out of interest, where did you get the idea that you _should_ do this manually? – Useless Mar 07 '19 at 13:24
  • If the destructor wasn't called then you would have to do it manually for **all** your variables. That would be error prone. So `C++` calls the destructor for all stack objects so you don't have to remember to do it. – Galik Mar 07 '19 at 13:32
  • When you put current through a light bulb it will produce light, but when you put light on a bulb it will not produce electricity. So at the end of object lifetime destructor is called. It does not mean if you call destructor that will end object lifetime. – Slava Mar 07 '19 at 13:39

4 Answers4

6

What you have here is undefined behavior as per the C++ standard:

As per [class.dtor]/16

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (6.8). [ Example: If the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined. —end example ]

You explicitly call the destructor for the automatic object objD with this statement:

objD.~Derived();

And the implicit destruction of the object is invoked at the end of its scope the closing }.

P.W
  • 26,289
  • 6
  • 39
  • 76
  • 1
    Corollary: don't use the explicit in-place destructor unless you had used placement new. The need to use placement new constructor and explicit in-place destructor is rare, and usually an advanced C++ programming technique (e.g., template containers). – Eljay Mar 07 '19 at 14:39
4

You create an object on the stack. This object has automatic lifetime managed by its surrounding scope. If you manually invoke the destructor, you do what the compiler does for you, and you end up with undefined behavior.

lubgr
  • 37,368
  • 3
  • 66
  • 117
2

you call the destructor, c++ have an automated call for destructor after the main function, or after the object is not in used and then the destructor call. you do double "free"

alon
  • 220
  • 1
  • 16
2

Object destructors are always called when the object goes out of scope. That's a fundamental part of how C++ is designed, enabling memory-safe exceptions, RAII, etc. Manually calling the destructor first has no bearing on that, so if you call it yourself it will (most likely, this is UB) run twice as you can see.

Calling a destructor manually is almost always incorrect and will result in Undefined Behaviour. The one case where it's allowed is when you've created an object in separately-allocated memory via "placement new".

Stu
  • 71
  • 1
  • 4