I have a C++ program that uses a std::list containing instances of a class. If I call e.g. myList.push_back(MyClass(variable));
it goes through the process of creating a temporary variable, and then immediately copies it to the vector, and afterwards deletes the temporary variable. This is not nearly as efficient as I want, and sucks when you need a deep copy.
I would love to have the constructor of my class new
something and not have to implement a copy constructor just to allocate my memory for the second time and waste runtime. I'd also rather not have to immediately find the class instance from the vector/list and then manually allocate the memory (or do something horrible like allocate the memory in the copy constructor itself).
Is there any way around this (I'm not using Visual Studio BTW)?
How to Initialize a Vector in C++ Using the push_back() Method. push_back() is one out of the many methods you can use to interact with vectors in C++. It takes in the new item to be passed in as a parameter. This allows us to push new items to the last index of a vector .
So you can emplace_back does use the desired constructor to create the element and call copy constructor when it need to grow the storage. You can call reserve with enough capacity upfront to avoid the need to call copy constructor.
C++0x move constructors are a partial workaround: instead of the copy constructor being invoked, the move constructor would be. The move constructor is like the copy constructor except it's allowed to invalidate the source argument.
C++0x adds another feature which would do exactly what you want: emplace_back
. (N3092 §23.2.3) You pass it the arguments to the constructor, then it calls the constructor with those arguments (by ...
and forwarding) so no other constructor can ever be invoked.
As for C++03, your only option is to add an uninitialized state to your class. Perform actual construction in another function called immediately after push_back
. boost::optional
might help you avoid initializing members of the class, but it in turn requires they be copy-constructible. Or, as Fred says, accomplish the same thing with initially-empty smart pointers.
Ahem. In the interests of science, I've whipped up a tiny test program to check whether the compiler elides the copy or not:
#include <iostream> #include <list> using namespace std; class Test { public: Test() { cout<<"Construct\n"; } Test(const Test& other) { cout<<"Copy\n"; } Test& operator=(const Test& other) { cout<<"Assign\n"; return (*this); } }; Test rvo() { return Test(); } int main() { cout<<"Testing rvo:\n"; Test t = rvo(); cout<<"Testing list insert:\n"; list<Test> l; l.push_back(Test()); }
And here's my output on MSVC++2008:
Testing rvo: Construct Testing list insert: Construct Copy
It's the same for both debug and release builds: RVO works, temporary object passing isn't optimized.
If I'm not mistaken, the Rvalue references being added in the C++0x standard are intended to solve this very problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With