crbah
crbah

Reputation: 336

Why is the destructor not called for stack variable when using assignement?

This stupid code snipped already took my 2 hours, I cannot figure out why the destructor of the first element, the one with size 7, not called? What happens to the memory allocated for new uint16_t[7]?

#include <iostream>

using namespace std;

struct Node
{
    Node(uint16_t n) : p(new uint16_t[n]) {
        cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
        for(uint16_t i=0; i<n; i++) p[i] = n;
    }

    ~Node() {
        cout<<"Destructor for p[0] = "<< *p <<" with memory addr: "<<p<<endl;
        delete[] p;
    }

    uint16_t *p;
};

int main()
{
    {
        Node nd1(7);
        {
            nd1 = Node(3);
            cout << "1st place holder" << endl;
        }
        cout << "2nd place holder" << endl;
    }

    return 0;
}

The output is

Constructed with size= 7, memory addr: 0x158cc20                                                                                                                                   
Constructed with size= 3, memory addr: 0x158cc40                                                                                                                                   
Destructor for p[0] = 3 with memory addr: 0x158cc40                                                                                                                                
1st place holder                                                                                                                                                                   
2nd place holder                                                                                                                                                                   
Destructor for p[0] = 0 with memory addr: 0x158cc40                                                                                                                                
*** Error in `./a.out': double free or corruption (fasttop): 0x000000000158cc40 ***                                                                                                
Aborted (core dumped) 

Upvotes: 3

Views: 113

Answers (2)

Guillaume Racicot
Guillaume Racicot

Reputation: 41760

This code: nd1 = Node(3); does not what you expect.

It does not replace nd1 with Node(3) and kill the old nd1.

What it does is it creates a new temporary node instance Node(3) and copy the value of every members into nd1. So both the temporary and nd1 contain a pointer that points to the same address. At that point, you leaked the memory nd1 allocated at the start of the program since no pointer is refering to it but you didn't deleted it.

When the temporary dies, nd1 points to dead memory. When nd1 runs its destructor at the second }, it delete the same pointer again hence your error.


To fix this, you'll have to implement what is called the rule of five or the rule of zero.

The easiest is the rule of zero. Simply use unique_ptr and the destruction happens as expected:

struct Node
{
    Node(uint16_t n) : p(std::make_unique<uint16_t[]>(n)) {
        cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
        for(uint16_t i=0; i<n; i++) p[i] = n;
    }

    std::unique_ptr<uint16_t[]> p;
};

int main()
{
    {
        Node nd1(7);
        {
            nd1 = Node(3); // assignement destroys the old buffer
            cout << "1st place holder" << endl;
        }
        cout << "2nd place holder" << endl;
    }

    return 0;
}

Upvotes: 3

eerorika
eerorika

Reputation: 238311

I cannot figure out why the destructor of the first element, the one with size 7, not called?

It is called. In fact, it is that destructor which causes the program to crash. The behaviour of the program is undefined because the destructor deletes the same pointer value that had previously been deleted by the destructor of the temporary object. And also before that it indirects through that invalid pointer.


What happens to the memory allocated for new uint16_t[7]?

The pointer to the memory was lost when you assigned over the object. This is called a memory leak.

Upvotes: 5

Related Questions