其他分享
首页 > 其他分享> > c – 在移动赋值和移动构造函数方面实现std :: swap

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 not t and rv refer to the same object.

标签:c,c11,stl,move-semantics
来源: https://codeday.me/bug/20190926/1822229.html