tags:

views:

324

answers:

3

I was wondering why the vector templates perform two allocations, when only one seems to be necessary.

For example this:

#include <vector>
#include <iostream>

class A {
    public:
         A(const A &a) {
            std::cout << "Calling copy constructor " << this << " " << &a << "\n";
        }
         A() {
            std::cout << "Calling default constructor " << this << "\n";
        }
        ~A() {
            std::cout << "Calling destructor " << this << "\n"; 
        }
};

int main(int argc, char **argv)
{
    std::vector <A> Avec;

    std::cout << "resize start\n";
    Avec.resize(1);
    std::cout << "resize end\n";

    return 0;
}

Outputs:

resize start
Calling default constructor 0x7fff9a34191f
Calling copy constructor 0x1569010 0x7fff9a34191f
Calling destructor 0x7fff9a34191f
resize end
A: 

If you initialize objects that way the vector template creates objects by making a copy. If you don't want to call copy constructor you should make :

vector<A*> Avec;
avec.push_back(new A());

http://www.cplusplus.com/reference/stl/vector/vector/

red777
I think that this will alsa make two allocations: - One for the new A() - One for the copy of push_back()
ynimous
@ynimous: Not really, the code above changes the semantics so that the vector contains pointers. It will create an A element only once, while it will create and copy the pointer (which is assumingly faster).
David Rodríguez - dribeas
The problem with this approach is that you are changing the semantics of the code. Before objects were held by value inside the vector, and destruction of the vector implied the destruction of all contained elements. Now as the elements are held through a pointer the code must be adapted and the user must destroy all resources (A objects) manually. While you have reduced the number of A constructions the code is now more fragile and prone to resource leaks.
David Rodríguez - dribeas
+15  A: 

It isn't performing two allocations, it is creating an object by the default constructor to pass into resize, then copying that object into the new position, then destructing the argument.

If you look at the arguments to resize:

void resize(n, t = T())

It has as a defaulted argument a default constructed object of type T (this is the default constructor being called in your output). Then, within the function, it copies this into the correct position (this is the copy constructor). After the resize function ends, destroys the argument (the destructor call in the output).

Todd Gardner
A: 

Here is a guess:

  1. The compiler re-ordered the initial allocation of Avec until after the "resize start"
  2. The vector is initially allocated with 0 elements
  3. The resize gets the new element filled with a default A (which was achieved by createing a default A, copying it into the vector, and deleting the temporary.
dmckee