On implementing std::swap in terms of move assignment and move constructor

前端 未结 4 2116
刺人心
刺人心 2020-12-05 15:54

Here is a possible definition of std::swap:

template
void swap(T& a, T& b) {
  T tmp(std::move(a));
  a = std::move(b);
          


        
4条回答
  •  忘掉有多难
    2020-12-05 16:17

    [res.on.arguments] is a statement about how the client should use the std::lib. When the client sends an xvalue to a std::lib function, the client has to be willing to pretend that the xvalue is really a prvalue, and expect the std::lib to take advantage of that.

    However when the client calls std::swap(x, x), the client isn't sending an xvalue to a std::lib function. It is the implementation that is doing so instead. And so the onus is on the implementation to make std::swap(x, x) work.

    That being said, the std has given the implementor a guarantee: X shall satisfy MoveAssignable. Even if in a moved-from state, the client must ensure that X is MoveAssignable. Furthermore, the implementation of std::swap doesn't really care what self-move-assignment does, as long as it is not undefined behavior for X. I.e. as long as it doesn't crash.

    a = std::move(b);
    

    When &a == &b, both the source and target of this assignment have an unspecified (moved-from) value. This can be a no-op, or it can do something else. As long as it doesn't crash, std::swap will work correctly. This is because in the next line:

    b = std::move(tmp);
    

    Whatever value went into a from the previous line is going to be given a new value from tmp. And tmp has the original value of a. So besides burning up a lot of cpu cycles, swap(a, a) is a no-op.

    Update

    The latest working draft, N4618 has been modified to clearly state that in the MoveAssignable requirements the expression:

    t = rv
    

    (where rv is an rvalue), t need only be the equivalent value of rv prior to the assignment if t and rv do not reference the same object. And regardless, rv's state is unspecified after the assignment. There is an additional note for further clarification:

    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.

提交回复
热议问题