-3

This is a simple test:

#include <iostream>
#include <vector>

using namespace std;

class C
{
public:
    int _a;
    C(int a) { cout << "constructor C: " << (_a = a) << endl; }
    ~C()     { cout << "destructor C: "<< _a << endl; }
};

int main()
{
    vector<C> vec;

    for(int i=0; i<2; i++)
        vec.push_back(i+1);

    cout << "Go out --->\n";
    return 0;
}

Output:

constructor C: 1
destructor C: 1
constructor C: 2
destructor C: 1
destructor C: 2
Go out --->
destructor C: 1
destructor C: 2

It looks not so funny when C is a real class with responsible destructor. Any suggestions? Thank you in advance.

  • 1
    same issue as here -> http://stackoverflow.com/q/2745350/476681 – BЈовић Mar 21 '14 at 12:06
  • You should really define (or forbid!) a full set of constructors and assignment operators for non-trivial classes like this ;-). Then you would see (and properly implement) or forbid assignments and copyings of your objects, e.g. in and out of containers. BЈовић's link illustrates the issues. – Peter - Reinstate Monica Mar 21 '14 at 12:14
  • Interestingly we have three destructions for 1, but "only" two for 2. The reason is the vector growing by reallocation, thereby copying the previous elements (here 1) and destroying the old ones. As noted, the copying is not logged, but the destruction is. Ah I see, Vlad made the same observation :-) – Peter - Reinstate Monica Mar 21 '14 at 12:39

2 Answers2

5

You get multiple class destructor logs because there is object copy when adding object in a vector. Log also in the copy contructor, you'll see it balances out. As indicated in the comments, if you are using C++11, also log in the move constructor.

That is why if object construction is expansive, you use pointers(smart_ptr) in vector. Or reserve enough space and use emplace_back(again if using C++11).

Eric Fortin
  • 7,533
  • 2
  • 25
  • 33
1

constructor C: 1

is called for creating temporary object C( 1 ) as argument of vec.push_back(i+1); when i =0

destructor C: 1

this temporary object was copied in an object of the vector and after that it was deleted.

constructor C: 2

is called for creating temporary object C( 2 ) as argument of vec.push_back(i+1); when i =1

The vecttor need to allocate a new memory region that to accomodate the second element. So it reallocates the memory and copies the first element in the new memory.

If you would call member function reserve

vector<C> vec;
vec.reserve( 2 );

then there would not be the reallocation and you would not see the next output.

destructor C: 1

the first element of the vector in old region memory is deleted

destructor C: 2

the temporary object was copied in an object of the vector and after that it was deleted.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335