为什么我需要使用std :: Move在Move-Constructor的初始化列表中
Why do I need to use std::move in the initialization list of a move-constructor?
假设我有一个(琐碎的)类,它是可移动的构建和移动 - 可分配但不可复制构建或副本分配的类别:
class movable
{
public:
explicit movable(int) {}
movable(movable&&) {}
movable& operator=(movable&&) { return *this; }
movable(const movable&) = delete;
movable& operator=(const movable&) = delete;
};
这很好:
movable m1(movable(17));
当然,这是不起作用的,因为m1
不是RVALUE:
movable m2(m1);
,但是,我可以将m1
包装在std::move
中,将其施放为rvalue-reference,以使其起作用:
movable m2(std::move(m1));
到目前为止,一切都很好。现在,假设我有一个(同样琐碎的)容器类,它具有一个值:
template <typename T>
class container
{
public:
explicit container(T&& value) : value_(value) {}
private:
T value_;
};
但是,这不起作用:
container<movable> c(movable(17));
编译器(我尝试过clang 4.0和G 4.7.2)抱怨说我正在尝试在container
的初始化列表中使用movable
的删除复制构建器。同样,将value
包装在std::move
中使其起作用:
explicit container(T&& value) : value_(std::move(value)) {}
但是为什么在这种情况下需要std::move
?value
不是movable&&
类型吗?value_(value)
与movable m1(movable(42))
有何不同?
那是因为 value
是命名变量,因此是lvalue。需要std::move
将其归还为RVALUE,以便将T
的移动构造人过载匹配。
用另一种方式说:rvalue参考可以 bind 与rvalue结合,但它本身并不是一个rvalue。这只是一个参考,在表达中,它是一个lvalue。从中创建一个表达式的唯一方法是铸造。
value_(value)
与movable m1(movable(42))
有何不同?
命名的rvalue参考是一个lvalue(因此将绑定到已删除的副本ctor),而临时是一个rvalue(特定于特定的prvalue)。
。 §5 [expr] p6
[...]通常,此规则的效果是,命名的rvalue参考被视为lvalues,对对象的未命名rvalue引用被视为xvalues [...]
与示例同样的
:
A&& ar = static_cast<A&&>(a);
表达式
ar
是lvalue。
上面的引号来自非规范性笔记,但是一个足够的解释,因为第5条的其余部分进行说明了哪些表达式唯一 create xvalues †(aka),只有指定的表达式和其他任何人都不会创建xvalues)。另请参阅此处以获取详尽的列表。
†xvalues是一个子组,其中Prvalues是另一个子组。请参阅此问题以进行解释。
- 瓦尔格林德:数学函数"Conditional jump or move depends on uninitialised value(s)"
- Usages of std::move
- 在C++中对T*类型执行std::move的意外行为
- 关于std::move的使用,是否有编译警告
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 通过实例理解std::move及其目的
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 是否可以在 C++03 中定义'move-and-swap idiom'等效项
- 返回一个带有 std::move 的对象并链接函数
- '[](std::list& list)<int>{return std::move(list)}(list)' 是否保证将 'list' 留空?
- 为什么字符串的 move() 会改变内存中底层数据的位置?
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- 为什么当我为 for(auto& it : myUnorderedMap) {... = std::move(it.second)} 时,我会得到一个 const 引用?
- 添加自定义析构函数时,Move 构造函数在派生类中消失
- 将向量从 N1 缩小到 N2 项,而不触发默认构造函数并仅使用 move 语义
- CPP 中的瓦尔格林德和记忆泄漏:"Conditional jump or move depends on uninitialised values"
- std::move a const std::vector in a lambda capture
- "std::forward"和"std::move"真的不生成代码吗?
- std::vector move 而不是交换到空 vector 并释放存储
- 是否有必要使用 std::move?这不是已经是一个右值参考了吗?