c – 在移动赋值和移动构造函数方面实现std :: swap
作者:互联网
这是std :: swap的可能定义:
template<class T>
void swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
我相信
> std :: swap(v,v)保证没有效果
> std :: swap可以如上实现.
以下引用似乎暗示这些信念是矛盾的.
17.6.4.9函数参数[res.on.arguments]
1 Each of the following applies to all arguments to functions defined
in the C++ standard library, unless explicitly stated otherwise.…
- If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to
this argument. [ Note: If the parameter is a generic parameter of the
form T&& and an lvalue of type A is bound, the argument binds to an
lvalue reference (14.8.2.1) and thus is not covered by the previous
sentence. — end note ] [ Note: If a program casts an lvalue to an
xvalue while passing that lvalue to a library function (e.g. by
calling the function with the argument move(x)), the program is
effectively asking that function to treat that lvalue as a temporary.
The implementation is free to optimize away aliasing checks which
might be needed if the argument was an lvalue. —endnote]
(感谢Howard Hinnant providing the quote)
设v是从标准模板库中取出的某种可移动类型的对象,并考虑调用std :: swap(v,v).在行a = std :: move(b);在上面,在T :: operator =(T&& t)内是这个==& b的情况,所以参数不是唯一的引用.这违反了上面的要求,因此当从std :: swap(v,v)调用时,行a = std :: move(b)会调用未定义的行为.
这里有什么解释?
解决方法:
[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的实现并不真正关心自移动赋值的作用,只要它不是X的未定义行为即可.只要不崩溃.
a = std::move(b);
当& a ==& b时,此分配的源和目标都具有未指定的(移动的)值.这可以是无操作,也可以做其他事情.只要它不崩溃,std :: swap就能正常工作.这是因为在下一行:
b = std::move(tmp);
无论从前一行进入a的值是什么,都将从tmp获得一个新值.并且tmp具有a的原始值.因此,除了烧掉大量的cpu周期外,swap(a,a)也是一个无操作.
更新
已修改latest working draft, N4618以清楚地表明在MoveAssignable要求中的表达式:
t = rv
(其中rv是一个rvalue),如果t和rv不引用同一个对象,则t只需要在赋值之前为rv的等效值.而且无论如何,rv的状态在分配后都没有指定.还有一个说明需要进一步说明:
rv
must still meet the requirements of the library component that is using it, whether or nott
andrv
refer to the same object.
标签:c,c11,stl,move-semantics 来源: https://codeday.me/bug/20190926/1822229.html