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

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

在 VC++ 2019 中,我不能 emplace_back 只移动类型的(右值)list

#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()));
}

尝试在 VC++ 2019 中构建会出现以下编译错误:

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

显然,VC++ 正在尝试为 A 实例化(左值)复制构造函数,它(正确地)不存在,因为我已经明确定义了 [= 的构造函数之一17=].

我认为通过从另一个 list 移动到 vector 就地实例化 list 应该是有效的 - 即 list class 确实有一个 move constructor,我认为它应该简单地导致新的 list 取得(移出的)list 中元素的所有权,而不需要任何副本。

实际上,使用Wandbox,same code builds and runs without error使用GCC和Clang。

有人可以解释为什么这段代码不能在 VC++ 2019 中编译吗?我是否有误解 - 为什么(左值)复制构造函数在上面的代码中被 VC++ 编译器实例化实际上是否有正当理由?


备注

std::move(...) 不存在时,VC++ 中也会出现同样的错误;即此行发生相同的错误:

v.emplace_back(ListOfA());

MSVC 使用 std::list 的复制构造函数,因为它的移动构造函数正在抛出。在重新分配期间,如果移动构造函数抛出,std::vector 无法提供标准要求的强异常保证。

在你的例子中,向量在重新分配之前没有任何元素,因此看起来没有调用复制构造函数,但这并不意味着不需要复制构造函数。

std::list 在 libstdc++ 和 libc++ 中有 noexcept 移动构造函数。这是允许的,但不是标准要求的。