Before C++11 introduced move semantics, the generic implementation of std::swap
had no choice but to do two copies. Conceptually, this:
template <class T>
void swap(T &a, T &b)
{
T t(a);
a = b;
b = t;
}
Notice that this generic std::swap
doesn't know anything about internals of the object passed in (because it can be called with an arbitrary user type, for example), and thus has to do copies. Note that for containers, this means copying the elements.
Providing an optimised member function swap
which just re-points some internal pointers is therefore a huge performance win.
Since move semantics were introduced, the generic swap can be made more efficient using moves. Again, conceptually:
template <class T>
void swap(T &a, T &b)
{
T t(::std::move(a));
a = ::std::move(b);
b = ::std::move(t);
}
Of course, in practice, it probably has requirements about the move operations involved being non-throwing, and all sorts of extra bits.
With move semantics in place, the optimised member versions are perhaps less important than they were before. But it's still possible that with knowledge of the exact implementation details of a type, swapping it can be faster than three generic moves.
In addition to the discussion above, notice that type-specific overloads of std::swap
exist for almost all types defined in the standard library. What these overloads do is simply call the optimised swap
member function on one of the operands. That way, you have the best of both worlds: a generic free function swap
which can be called with anything, but which has optimised implementations for everything the standard library is aware of.
It would be possible to forego the member functions and provide the optimised implementations inside the std::swap
overloads directly, but this would mean they'd likely need to be friended and could be perceived as worse accessible to user code.