std::list of move-only type: Cannot emplace into std::vector in VC++

Viewed 1161

In VC++ 2019, I cannot emplace_back an (rvalue) list of a move-only type.

#include <vector>
#include <list>

struct A
{
    A(A&&) {}
};

using ListOfA = std::list<A>;

int main()
{
    std::vector<ListOfA> v;

    // Build error in VC++ 2019
    // No error in Clang and GCC C++11 - C++2a
    v.emplace_back(std::move(ListOfA()));
}

Attempting to build in VC++ 2019 gives the following compile error:

'A::A(const A &)': attempting to reference a deleted function

Clearly, VC++ is attempting to instantiate the (lvalue) copy constructor for A, which (correctly) does not exist because I have explicitly defined one of the constructors for A.

I would think that it should be valid to instantiate a list in-place in a vector by moving from another list - that is, the list class does have a move constructor which I'd think should simply cause the new list to take ownership over the elements in the (moved-from) list, without requiring any copies.

In fact, using Wandbox, the same code builds and runs without error using GCC and Clang.

Can somebody explain why this code does not compile in VC++ 2019? Do I have a misunderstanding - is there in fact a valid reason why the (lvalue) copy constructor is being instantiated by the VC++ compiler in the code above?


Note

The same error occurs in VC++ when the std::move(...) is not present; i.e. the same error occurs with this line:

v.emplace_back(ListOfA());

1 Answers

MSVC uses the copy constructor of std::list because its move constructor is throwing. During reallocation, if the move constructor throws, std::vector cannot provide strong exception guarantee as required by the standard.

In your case, the vector does not have any element before reallocation, so it appears that the copy constructor is not called, but that doesn't mean the copy constructor is not needed.

std::list in libstdc++ and libc++ has noexcept move constructor. This is permitted but not required by the standard.

Related