How to write a swap functon for your own class? This is especially useful when default swap behavior is too heavy for your class. You can imagine this is how std
‘s implementation
1 | namespace std { |
And if you have any classes implement pimpl idiom
like such
1 | class WidgetImpl { |
If you want to swap such object, you only need to swap the implementation pointer instead of the whole object. That’s when you need to write your own swap
method. Most likely swap
needs access to private members, so you will write a member swap
method
1 | class Widget { |
And if you want to support conventional std::swap
function, you can add a specialized version for std::swap
which calls the member swap
as such
1 | namespace std { |
You may wonder why we need using std::swap
in above member swap
example. In above case, it seems not necessary because we know pImpl
is pointer type and std::swap
supports such. So you could use std::swap
directly. But above way of calling swap
works for all cases. Let’s discuss what’s the special case we need to consider.
You may have guessed it, it’s when user defined class is a template class. When you make Widget
and WidgetImpl
class templates
1 | template<typename T> |
You would natually provide following specialized std::swap
implementation
1 | namespace std { |
This won’t compile because you cannot partially specialize a function template error: function template partial specialization is not allowed
.
The common solution is to use overloading instead of total template specialization. But there is a problem doing so in std
namespace. It’s okay to totally specialize templates in std, but it’s not okay to add new templates (or classes or functions or anything else) to std
. Voilating such rule will lead to undefined behavior.
So what’s the solution to this? Creating a namespace and define a free swap
there.
1 | namespace WidgetStuff { |
For any user of swap
who may or may not know whether the class implements it’s own swap
, always bring std::swap
into scope by doing using std::swap
and then call swap
. This way, it will call cusomized swap
function if it’s available, otherwise, it will call std::swap
.
1 | template <typename T> |
At this point, we’ve discussed the default swap, member swaps, non-member swaps, specializations of std::swap
, and calls to swap, so let’s summarize the situation.
First, if the default implementation of swap
offers acceptable efficiency for your class or class template, you don’t need to do anything. Anybody trying to swap
objects of your type will get the default version, and that will work fine.
Second, if the default implementation of swap
isn’t efficient enough (which almost always means that your class or template is using some variation of the pimpl idiom), do the following:
- Offer a public
swap
member function that efficiently swaps the value of two objects of your type. For reasons I’ll explain in a moment, this function should never throw an exception. - Offer a non-member
swap
in the same namespace as your class or template. Have it call your swap member function. - If you’re writing a class (not a class template), specialize
std::swap
for your class. Have it also call your swap member function.
Finally, if you’re calling swap
, be sure to include a using
declaration to make std::swap
visible in your function, then call swap
without any namespace qualification.