25

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)
{}

1 Answer 1

20

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.

1
  • 2
    @dannissenbaum note that the move/copy is not called in your case, but must exist for the case where there was already existing content in the vector and it needed to resize. The complie time instance of the method does not know it it being called on an empty vector, so it must handle all code paths. Commented Dec 15, 2013 at 14:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.