开发者

How do STL containers copy objects?

I know STL containers like vector copies the object when it is added. push_back method looks like:

void push_back ( const T& x );

I am surprised to see that it takes the item as reference. I wrote a sample program to see how it works.

struct Foo
{
    Foo()
    {
        std::cout << "Inside Foo constructor" << std::endl;
    }

    Foo(const Foo& f)
    {
        std::cout << "inside copy constructor" << std::endl;
    }
};

Foo f;
std::vector<Foo> foos;
foos.push_back(f);

This copies the object and I can see it is calling copy-constructor.

My question is, when the push_back takes item as reference, how it is calling copy-constructor? Or am I missing so开发者_运维百科mething here?

Any thoughts..?


It probably uses "placement new" to construct the object in-place in its internal array. Placement new doesn't allocate any memory; it just places the object where you specify, and calls the constructor. The syntax is new (address) Class(constructor_arguments).

The copy constructor T::T(T const &) is called to create the copy in-place. Something like this (simplified):

template<T>
void vector<T>::push_back(T const &item) {
    // resize if necessary
    new (&d_array[d_size++]) T(item);
}

Note that T must have a copy constructor for this to work. By default (if you do nothing), it gets one for free. If you define it explicitly, it must be public for vector<T> to work.

Here's how GNU's libstdc++ does it, but I doubt that it'll be very enlightening. There is an allocator (the second template argument to vector) that makes it less straightforward.


The C++ SDK always takes const T & as function parameter for efficiency.

In your case if it take T as parameter, the copy action will be done twice, one for passing it to function push_back(f), one for internal adding it to the container. And by taking const T& as parameter only one copy is needed!


It uses the placement new operator and copy-constructs it to unitialized memory;

The placement new creates a new element at a specified adress in memory, in the vector case, the current end();

void push_back(const T& val){
::new (&*end()) T(val);
[increase end]
}

look at http://spotep.com/dev/devector.h which has quite clear code (as opposed to most STL implementations).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜