Ref. [Book] The C++ Programming Language

old-style swap

template<class T>
swap(T& a, T& b) // "old-style swap"
{
    T tmp {a}; // now we have two copies of a
    a = b; // now we have two copies of b
    b = tmp; // now we have two copies of tmp (aka a)
}

If T is a type for which it can be expensive to copy elements, such as string and vector, this swap() becomes an expensive operation.
we just wanted to move the values of a, b, and tmp around.

perfect swap

template<class T>
void swap(T& a, T& b) // "perfect swap" (almost)
{
    T tmp {static_cast<T&&>(a)}; // the initialization may write to a
    a = static_cast<T&&>(b); // the assignment may write to b
    b = static_cast<T&&>(tmp); // the assignment may write to tmp
}

The result value of static_cast<T&&>(x) is an rvalue of type T&& for x. An operation that is optimized for rvalues can now use its optimization for x. In particular, if a type T has a move constructor or a move assignment, it will be used.

template<class T> class vector {
    // ...
    vector(const vector& r); // copy constr uctor (copy r’s representation)
    vector(vector&& r); // move constr uctor ("steal" representation from r)
};

vector<string> s;
vector<string> s2 {s}; // s is an lvalue, so use copy constr uctor
vector<string> s3 {s+"tail"); // s+"tail" is an rvalue so pick move constr uctor

perfect swap

the standard
library provides a move() function: move(x) means static_cast<X&&>(x) where X is the type of x.
Given that, we can clean up the definition of swap() a bit:

template<class T>
void swap(T& a, T& b) // "perfect swap" (almost because it will swap only lvalues)
{
    T tmp {move(a)}; // move from a
    a = move(b); // move from b
    b = move(tmp); // move from tmp
}

Leave a Reply