Bja*_*une 10 c++ stl move-semantics c++11
以下是可能的定义std::swap:
template<class T>
void swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Run Code Online (Sandbox Code Playgroud)
我相信
std::swap(v,v) 保证没有效果std::swap 可以如上实现.以下引用似乎暗示这些信念是矛盾的.
17.6.4.9函数参数[res.on.arguments]
1除非另有明确说明,否则以下各项均适用于C++标准库中定义的函数的所有参数.
...
- 如果函数参数绑定到右值引用参数,则实现可以假定此参数是对此参数的唯一引用.[注意:如果参数是T &&形式的通用参数并且绑定了类型A的左值,则参数绑定到左值引用(14.8.2.1),因此不包含在前一句中. - 结束注释] [注意:如果程序在将左值传递给库函数时将左值转换为x值(例如通过使用参数move(x)调用函数),程序实际上会要求该函数处理该左值作为临时的.实现可以自由地优化别名检查,如果参数是左值,则可能需要这些检查.-endnote]
(感谢霍华德Hinnant(欣南特)用于提供报价)
让我们v从标准模板库中获取一些可移动类型的对象并考虑该调用std::swap(v, v).在该行a = std::move(b);以上,这是内部的情况T::operator=(T&& t)的是this == &b,这样的参数是不唯一的参考.这违反了上面的要求,因此该行在a = std::move(b)调用时调用未定义的行为std::swap(v, v).
这里有什么解释?
[res.on.arguments]是关于客户端应如何使用std :: lib的声明.当客户端向std :: lib函数发送xvalue时,客户端必须愿意假装xvalue确实是prvalue,并期望std :: lib利用它.
但是,当客户端调用std :: swap(x,x)时,客户端不会向std :: lib函数发送xvalue.这是实现,而是这样做.所以onus是在实现使std :: swap(x,x)工作.
话虽这么说,std给了实现者一个保证:X应该满足MoveAssignable.即使处于移动状态,客户端也必须确保X是MoveAssignable.此外,std::swap只要它不会崩溃,只要它不是XIe的未定义行为,实现并不真正关心自动分配的作用.
a = std::move(b);
Run Code Online (Sandbox Code Playgroud)
当&a ==&b时,此赋值的源和目标都具有未指定的(移动的)值.这可以是无操作,也可以做其他事情.只要它不崩溃,std :: swap就能正常工作.这是因为在下一行:
b = std::move(tmp);
Run Code Online (Sandbox Code Playgroud)
无论a前一行的价值是什么,都将获得一个新的价值tmp.并tmp具有原始价值a.所以除了烧掉很多cpu周期外,swap(a, a)还有一个无操作.
更新
在最新的工作草案,N4618已被修改,明确规定,在MoveAssignable规定的表达式:
t = rv
Run Code Online (Sandbox Code Playgroud)
(其中rv是rvalue),t只需rv要是赋值之前的等价值,如果t并且rv不引用同一个对象.无论如何,rv在任命之后,状态是未指定的.还有一个说明需要进一步说明:
rv还必须满足在使用它,无论是否在该库组件的要求t,并rv指向同一个对象.
| 归档时间: |
|
| 查看次数: |
2030 次 |
| 最近记录: |