【发布时间】:2019-10-30 03:05:28
【问题描述】:
在 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 的(左值)复制构造函数,但它(正确地)不存在,因为我已明确定义了 A 的构造函数之一。
我认为通过从另一个 list 移动来在 vector 中就地实例化 list 应该是有效的 - 也就是说,list 类确实有一个 move constructor 我' d 认为应该简单地使新的list 接管(移出)list 中的元素的所有权,而不需要任何副本。
其实使用Wandbox,same code builds and runs without error使用GCC和Clang。
有人可以解释为什么这段代码在 VC++ 2019 中无法编译吗?我是否有误解 - 实际上是否有正当理由说明(左值)复制构造函数在上面的代码中被 VC++ 编译器实例化?
注意
当std::move(...) 不存在时,VC++ 中也会出现同样的错误;即这一行出现同样的错误:
v.emplace_back(ListOfA());
【问题讨论】:
-
Clang 打印出一条有趣的消息:
warning: moving a temporary object prevents copy elision [-Wpessimizing-move] -
你不需要
std::move一个临时的。尝试摆脱std::move,看看VC会发生什么(gcc非常高兴)。 -
您可以通过查看所有错误消息转储来推断这一点,并查看调用了哪个
std::list构造函数。或者,向您的类添加一个复制构造函数,在复制构造函数中设置一个断点,然后查看调用堆栈。 -
事实上,
std::is_nothrow_move_constructible_v<ListOfA>在 gcc 9 中给出1在 MSVC 19 中给出0 -
当我实现复制构造函数并在那里和移动构造函数中放置断点时,只到达移动构造函数。未达到复制构造函数。尽管
std::is_nothrow_move_constructible_v<ListOfA>返回 false,但不知何故 VC++ 正在调用list移动构造函数
标签: c++ list visual-c++ move-semantics