tags:

views:

81

answers:

3

Here is the code:

#include <vector>
#include <iostream>

class A
{
public:
    A() { std::cout << __FUNCTION__ << "\n"; }
    ~A() { std::cout << __FUNCTION__ << "\n"; }

    A& operator=(const A&) { std::cout << __FUNCTION__ << "\n"; return *this;}
};

int main(int argc, char* argv[])
{
    std::vector<A> as;
    A a;
    as.push_back(a);
    as.push_back(a);
    return 0;
}

And here is the output I got:

A::A
A::~A
A::~A
A::~A
A::~A

I understand that the output of the first line is from the call to the c-tor from when 'a' is created. One of the calls to the d-tor's also belongs to a. What about the other three calls to A::~A(), where are they coming from? And why are there more calls to the d-tor than calls to the c-tor? How does the container clone 'a' when it adds copies to its elements? And finally, is the output implementation-defined or are there are other possible outputs?

+3  A: 

You need to add a copy constructor:

 A( const A& ) { std::cout << __FUNCTION__ << "\n"; }

The vector, like all other Standard Library containers, stores copies - these copies are made with the copy constructor. You should be aware however that there are several places where the compiler is allowed to elide copy construction, or even make extra copies, so your output may not be exactly what you are expecting.

anon
+2  A: 

To understand what happens, you are missing one method in A :

A(const A&) { std::cout << __FUNCTION__ << "(const A&)\n"; }

Then you see the output:

A()
A(const A&)
A(const A&)
A(const A&)
~A
~A
~A
~A

What happen is that, for each push_back the vector allocate a new contiguous array, copy the old content, and destroy it. If you count, the first copy constructor is for the first push_back, the second and third for the next push_back. The first destructor is for the second push_back, the two next for the destruction of the vector, the last one for the destruction of the variable a.

And by the way, this is completely implementation defined, as it is allowed to allocate by chunk, which would prevent quite a few copy/destruction. You can even so the chunks yourself by using vector::reserve(size_type n).

PierreBdR
A: 

As I'm sure you realise you are creating your "A" objects on the stack and they are then being copied into the array (as the other answers suggest) implicately using the copy constructor.

If your A objects are real data objects with data they own, or complex state that is difficult to copy you might want to consider storing pointers in your array rather than storing the objects directly. You will need to manage the memory yourself then, but it's a point worth considering.

int main(int argc, char* argv[])
{
    std::vector<A*> as;
    A *a = new A();
    as.push_back(a);
    as.push_back(a);
    return 0;
}

You would see the output:

A()

Since only one instance of the object has been created and the array is just storing copies of the pointer. Obviously, at some point you would need to delete the object itself via one of its pointers to ensure you get the memory back eventually.

xan