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).
精彩评论