Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

class object as vector element , destructor getting called too many times

Tags:

c++

destructor

#include <vector>
#include <iostream>
#include <memory>

using namespace std;

class A
{
    static int k;
    public:
    A(){k++ ; cout << "constructor : " <<k<< endl;};
    ~A(){k--; cout << "destructor : "  << k <<endl;};
    void show() { cout<<"current value of k = "<<k<<endl; }
};
int A::k = 0;
int main( )
{
    vector<A> test;
    test.push_back(A());
    test.emplace(test.end(), A()); 
    test[0].show();
    cout<<test.size()<<endl;
    return 0; 
}

Output:

constructor : 1

destructor : 0

constructor : 1

destructor : 0

destructor : -1

current value of k = -1

2

destructor : -2

destructor : -3

Why has the destructor been called too many times, as it should have been called just twice since the constructor only gets called twice? How to avoid this situation?

like image 379
user3798283 Avatar asked Apr 08 '16 09:04

user3798283


People also ask

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.

Can destructor be called multiple times?

According to the linked question, this is because the destructor is called multiple times for the pointer member, a consequence of the copy constructor being called multiple times when copying, causing an attempted deallocation of memory already deallocated.

How many times a destructor can be called?

Why is the destructor being called three times?

How do you stop a destructor in C++?

The best way to not call a particular destructor is to not create an instance of that object to begin with. Failing that, take the code you don't want to run out of the destructor.


2 Answers

A compiler-generated copy constructor is being used, which doesn't increment k.

Include that explicitly in your source code, and all will be well.

like image 141
Bathsheba Avatar answered Oct 16 '22 21:10

Bathsheba


You're making copies, but your trace output doesn't show that (and your k doesn't get incremented when it happens). So the "extra" destructor calls go with copy constructions.

You can remove one of the copies by using emplace properly:

test.emplace(test.end());
//                     ^ no A() here; that would be like doing test.push_back(A(A()))

but you still have a copy in the push_back itself.

Write a copy constructor so that your trace output accounts for those operations:

A(const A&) { k++; cout << "copy-constructor : " << k << endl; }

(I wouldn't bother with a move constructor, as that'll delete the copy assignment operator and all hell will break loose.)


Finished code:

#include <vector>
#include <iostream>
#include <memory>

using namespace std;

class A
{
    static int k;

public:
    A()         { k++; cout << "constructor : "      << k << endl; }
    ~A()        { k--; cout << "destructor : "       << k << endl; }
    A(const A&) { k++; cout << "copy-constructor : " << k << endl; }

    void show() { cout << "current value of k = " << k << endl; }
};

int A::k = 0;

int main()
{
    vector<A> test;

    test.push_back(A());
    test.emplace(test.end(), A());

    test[0].show();
    cout << test.size() << endl;
}

Output:

constructor : 1
copy-constructor : 2
destructor : 1
constructor : 2
copy-constructor : 3
copy-constructor : 4
destructor : 3
destructor : 2
current value of k = 2
2
destructor : 1
destructor : 0

(live demo)

like image 4
Lightness Races in Orbit Avatar answered Oct 16 '22 21:10

Lightness Races in Orbit