Search code examples
c++backemplace

Why does vector<T>::emplace_back, such that T has a deleted copy constructor, fail to compile?


I cannot compile the following dont_compile function. I don't understand why it doesn't work. But, it does work with list.

class Thing {
public:
    Thing() {}
    Thing(const Thing &) = delete;
};

int dont_compile(int argc, char ** argv)
{
    std::vector<Thing> v;
    v.emplace_back();

    return 0;
}

int compiles(int argc, char ** argv)
{
    std::list<Thing> v;
    v.emplace_back();

    return 0;
}

Here is the error from the compiler. Is it a bug?

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1752:31: error: call to deleted constructor of 'Thing'
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

... snip ...

note: 'Thing' has been explicitly marked deleted here
        Thing(const Thing &) = delete;

I don't really understand how _Up(...) is causing the copy constructor to be invoked.


Solution

  • It works when you have move constructor:

    #include <vector>
    
    class Thing {
    public:
        Thing() {}
        Thing(const Thing &) = delete;
        Thing(Thing&&) = default;
    };
    
    int main() {
        std::vector<Thing> v;
        v.emplace_back();
        return 0;
    }
    

    The type requirements of std::vector::emplace_back can provide more information.