Search code examples
c++constructordestructorplacement-new

How does the compiler knows that a second destructor has to be called, for an object constructed twice, at the same address?


In the code that follows, the object sub in class C is constructed twice. The first construction calls the default ctor Sub() and the second construction uses placement new to reconstruct this object in the same address.

Therefore the destructors are also called twice. The first call uses the direct call to the Sub dtor in ~C() and the second call is invoked after the end of main(), I believe, by the atexit() function.

Given that the object sub is reconstructed at the same address, how does the compiler knows that the second destructor must be called after main()? Where does he keep this information?

#include <iostream>
using namespace std;

struct Table
{
    int i;
    Table(int j) : i(j) {}
};

struct Sub
{
    Table* pTable;
    Sub(int j) { cout << "ctor placement new" << endl; pTable = new Table(j); }
    Sub() { cout << "ctor default" << endl; pTable = 0; }
    ~Sub() { if( pTable ) cout << "dtor placement new" << endl;
             else         cout << "dtor default" << endl;
             delete pTable; pTable = 0; }
};

class C
{
    Sub sub;

    public:
    C() { new (&sub) Sub(10); }
    ~C() { (&sub)->~Sub(); }
};

int main()
{
    C c;
}

Solution

  • Although this is clearly undefined behavior, if you reason out what's happening, it's pretty obvious.

    You create an object of class C. In that process, the default constructor of Sub is called implicitly. pTable is 0. Then, you explicitly call the int constructor, which initializes pTable. Then, in the destructor, you explicitly call Sub's destructor. pTable is set to 0 again. Then, at the end of C's destructor, Sub's destructor is called again, implicitly.

    It's not at the end of main that it's happening. It's happening at the end of C's destructor.