c++visual-c++stdstdvectormove-semantics

Only copiable type not accepted in msvc std::vector implementation


In the following code:

struct copy_only
{
    copy_only() = default;
    copy_only(const copy_only&)            = default;
    copy_only& operator=(const copy_only&) = default;
    copy_only(copy_only&&)                 = delete;
    copy_only& operator=(copy_only&&)      = delete;
    ~copy_only()                           = default;
};


std::vector<copy_only> v;
copy_only c{};
v.push_back(c);

On MSVC we get the error:

error C2280: 'copy_only::copy_only(copy_only &&)': attempting to reference a deleted function

This comes from within the vector implementation where push_back(const&) calls emplace_back implementation:

note: while compiling class template member function 'void std::vector<copy_only,std::allocator<copy_only>>::push_back(const _Ty &)'

note: see reference to function template instantiation '_Ty &std::vector<_Ty,std::allocator<_Ty>>::_Emplace_one_at_back<const _Ty&>(const _Ty &)' being compiled

This compiles with gcc and clang. Is this just a massive MSVC compiler bug on the simplest vector example? Or is there some standard thing that would prevent this usage that gcc and clang are just glossing over?

Live example.


Solution

  • vector::push_back() has a Precondition of "T is Cpp17CopyInsertable into X", and Cpp17CopyInsertable implies Cpp17MoveInsertable according to [container.alloc.reqmts-2.4]:

    T is Cpp17CopyInsertable into X means that, in addition to T being Cpp17MoveInsertable into X, the following expression is well-formed:

     allocator_traits<A>::construct(m, p, v)
    

    and its evaluation causes the following postcondition to hold: The value of v is unchanged and is equivalent to *p.

    Since your class is not Cpp17MoveInsertable and therefore not Cpp17CopyInsertable, which violates the Precondition of push_back() and leads into undefined behavior.