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
swapmember 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
swapin 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::swapfor 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.