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.
TL;DR: This is a poorly written class.
Copyable classes shouldn't actively resist moving, even if they don't want to have any custom move behavior.
Instead they should let moving fall back to copying, which happens automatically if you don't write move operations at all, instead of explicitly deleting them.
This isn't just something that doesn't play nice with std::vector
. This will constantly cause issues, because nobody expects classes to do this.
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 intoX
means that, in addition toT
being Cpp17MoveInsertable intoX
, 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.
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