Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is copy constructor called in call to std::vector::emplace_back()?

Tags:

It is my understanding that the purpose of std::vector::emplace_back() is specifically to avoid calling a copy constructor, and instead to construct the object directly.

Consider the following code:

#include <memory> #include <vector> #include <boost/filesystem.hpp>  using namespace std;  struct stuff {     unique_ptr<int> dummy_ptr;     boost::filesystem::path dummy_path;     stuff(unique_ptr<int> && dummy_ptr_,           boost::filesystem::path const & dummy_path_)         : dummy_ptr(std::move(dummy_ptr_))         , dummy_path(dummy_path_)     {} };  int main(int argc, const char * argv[]) {      vector<stuff> myvec;      // Do not pass an object of type "stuff" to the "emplace_back()" function.     // ... Instead, pass **arguments** that would be passed     // ... to "stuff"'s constructor,     // ... and expect the "stuff" object to be constructed directly in-place,     // ... using the constructor that takes those arguments     myvec.emplace_back(unique_ptr<int>(new int(12)), boost::filesystem::path());  } 

For some reason, despite the use of the emplace_back() function, this code fails to compile, with the error:

error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' [...] This diagnostic occurred in the compiler generated function 'stuff::stuff(const stuff &)'

Notice that the compiler attempted to create (and use) the COPY CONSTRUCTOR. As I've discussed above, it's my understanding that the purpose of emplace_back() is to avoid the use of the copy constructor.

Of course, since the compiler is attempting to create and call the copy constructor, there's no way the code would compile even if I defined the copy constructor for stuff, because the std::unique_ptr cannot be used in a copy constructor. Hence, I would very much like to avoid the use of a copy constructor (in fact, I need to avoid it).

(This is VS 11.0.60610.01 Update 3 on Windows 7 64-bit)

Why is the compiler generating, and attempting to use, the copy constructor, even though I am calling emplace_back()?


Note (in response to @Yakk's answer):

Explicitly adding the move constructor, as follows, resolves the problem:

stuff(stuff && rhs)     : dummy_ptr(std::move(rhs.dummy_ptr))     , dummy_path(rhs.dummy_path) {} 
like image 270
Dan Nissenbaum Avatar asked Dec 15 '13 13:12

Dan Nissenbaum


People also ask

Does Emplace_back call copy constructor?

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.

What is Emplace_back in vector?

C++ Vector Library - emplace_back() Function The C++ function std::vector::emplace_back() inserts new element at the end of vector. Reallocation happens if there is need of more space. This method increases container size by one.

Should I use Emplace_back or Push_back?

You should definitely use emplace_back when you need its particular set of skills — for example, emplace_back is your only option when dealing with a deque<mutex> or other non-movable type — but push_back is the appropriate default. One reason is that emplace_back is more work for the compiler.


1 Answers

Visual Studio 2013 and earlier fails to write default move constructors for you. Add a simple explicit move constructor to stuff.

A push or emplace back can cause stuff to be moved if it needs to reallocate, which in your case copies, as stuff has no move.

It is a msvc bug.

like image 119
Yakk - Adam Nevraumont Avatar answered Oct 21 '22 11:10

Yakk - Adam Nevraumont