仅移动类型的std :: list:在VC ++中无法放入std :: vector

时间:2019-06-16 03:01:43

标签: c++ list visual-c++ move-semantics

在VC ++ 2019中,我无法emplace_back和仅移动类型的{rvalue} 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的(左值)复制构造函数,(正确地)该构造函数不存在,因为我为A明确定义了其中一个构造函数。

我认为通过从另一个list移动实例化vector到位的list应该是有效的-也就是说,list类确实可以拥有一个move constructor,我认为应该只是使新的list拥有(移出的)list中元素的所有权,而无需任何副本。

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

有人可以解释为什么此代码无法在VC ++ 2019中编译吗?我有一个误会吗-VC ++编译器在上面的代码中实例化(lvalue)复制构造函数,实际上是否有正当理由?


注意

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

v.emplace_back(ListOfA());

1 个答案:

答案 0 :(得分:3)

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

在您的情况下,向量在重新分配之前没有任何元素,因此似乎没有调用复制构造函数,但这并不意味着不需要复制构造函数。

libstdc ++和libc ++中的

std::list具有noexcept的move构造函数。这是允许的,但不是标准要求的。