c++language-lawyerc++20stdvectorcopy-constructor

Copying of std::vector filled with neither copy constructible nor copy assignable elements


Consider I have a class A that is neither copy constructible nor copy assignable, but has any-like constructor A(auto &&). Can I create copies of std::vector<A> then?

#include <concepts>
#include <vector>

struct A {
    A() {}
    A(const A&) = delete;
    A(auto &&) {}
    A & operator=(const A&) = delete;
};
static_assert(!std::copy_constructible<A>);

const std::vector<A> v(3);
auto w( v ); // fails only in libstdc++

In GCC with libstdc++ the compilation fails with rather long error message, where the essential part seems to be:

/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
   90 |       static_assert(is_constructible<_ValueType, _Tp>::value,
      |                                                        ^~~~~

However, both MSVC and Clang with libc++ accept the program just fine. Online demo: https://gcc.godbolt.org/z/vhdEGn5sv

Which implementation is correct here?


Solution

  • auto w( v ) is exactly the condition in [container.reqmts]:

    Preconditions: T is Cpp17CopyInsertable into X

    which means that:

    the following expression is well-formed:

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

    In the extant case, m is an allocator of type std::allocator<A>, p is a pointer of type A*, and v is an expression that denotes an lvalue of type A or const A or an rvalue of type const A.

    This is equivalent to:

    ::new (voidify(*p)) A(v) // when v is lvalue of type A or const A
    

    This fails when v is an lvalue of type const A, so the precondition is violated, so the program has undefined behavior and anything is valid.

    In practice, the standard library has license to construct from A& or const A& and they make different choices. Constructing from A& will by overload resolution choose the greedy template.