Here is a possible definition of std::swap
:
template<class T>
void swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
I believe that
std::swap(v,v)
is guaranteed to have no effects andstd::swap
can be implemented as above.
The following quote seems to me to imply that these beliefs are contradictory.
17.6.4.9 Function arguments [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]
(thanks to Howard Hinnant for providing the quote)
Let v
be an object of some movable type taken from the Standard Template Library and consider the call std::swap(v, v)
. In the line a = std::move(b);
above, it is the case inside T::operator=(T&& t)
that this == &b
, so the parameter is not a unique reference. That is a violation of the requirement made above, so the line a = std::move(b)
invokes undefined behavior when called from std::swap(v, v)
.
What is the explanation here?
std::move(v,v)
is guaranteed to do nothing and also it is undefined behavior. Those two statements cannot both be right. So something is wrong with my reasoning or with the assumptions. Which thing is wrong? – Ollystd::swap(v,v)
, notstd::move(v,v)
, right? – Dekelesstd::swap(v,v)
. – Ollystd::move(x)
is passed to a s.l. function, the parameter is not a unique reference (sincex
the caller still exists); apparently the uniqueness assumption is only among the references the implementation can see. If UB had been invoked here, it would cast a lot of doubt – Eisinger