Item 25: consider implementing a swap valid tive C ++ note, swapvalid tive
Item 25: Consider support for a non-throwing swap.
The Swap function was initially introduced by STL and has become a key function in exceptional security programming (see Item 29). It also solves the problem of self-assignment (see Item 11: assignment operator self-assignment).std
Its basic implementation is intuitive:
namespace std{ template<typename T> void swap(T& a, T& b){ T tmp(a); a = b; b = tmp; }}
As you can see, the above Swap is implemented by assigning values and copying structures. Sostd::swap
Exception security is not provided, but due to the importance of Swap operations, we should implement exception security for custom classes. This is the focus of this section.
Class Swap
Do not mention exceptional security first, sometimesstd::swap
Not efficient (for custom types ). For example, in a class designed using pimpl idiom (see Item 31), you only need to exchange pointers to implement objects:
Class WidgetImpl; class Widget {// a class of pimpl idiom WidgetImpl * pImpl; // point to the Widget implementation (data) public: Widget (const Widget & rhs );}; namespace std {template <> // The template parameter is null, indicating that this is a fully-specialized void swap <Widget> (Widget & a, Widget & B) {swap (. pImpl, B. pImpl); // you only need to swap the pointers of their object classes }}
The above Code cannot be compiled becausepImpl
Is a private member! So,Widget
Aswap
Member function or friend function. In practice, a member function is provided:
Class Widget {public: void swap (Widget & other) {using std: swap; // Why? See the following swap (pImpl, other. pImpl );}};
Next, we will continue to make it special.std::swap
Because this is the Swap function that can be called:
Namespace std {template <> void swap <Widget> (Widget & a, Widget & B) {a. swap (B); // call the member function }}
So far, we have achieved perfection.swap
Code. The above implementation is consistent with that of the STL container: provide a commonswap
Member functions, and specialstd::swap
To call the member function.
Class template Swap
WhenWidget
Is a class template, the situation is more complex. According to the above Swap implementation method, you may write as follows:
Template <typename T> class WidgetImpl {...}; template <typename T> class Widget {...}; namespace std {template <typename T> // The angle brackets after swap indicate that this is a special feature, not a heavy load. // The type list in swap <> is a special case of the type list in template <>. Void swap <Widget <T> (Widget <T> & a, Widget <T> & B) {a. swap (B );}}
The tragedy is that the above Code cannot be compiled. C ++ allows bitwise class templates, but does not allow bitwise function templates (although some compilers can compile ). So we simply don't want to be special, so we will reload it.std::swap
Function template:
Namespace std {template <typename T> // note that swap is not followed by Angle brackets. This is a new template function. // The current namespace already has functions with the same name, so the function is overloaded. Void swap (Widget <T> & a, Widget <T> & B) {a. swap (B );}}
Here we reloadstd::swap
, Which is equivalentstd
A function template is added to the namespace. This is not allowed in the C ++ standard! In the C ++ standard, the customer can only specializestd
But not allowed instd
Add any new template to the namespace. Although the above Code can be compiled in Some compilers, it will lead to undefined behaviors, so do not do this!
What should we do? The solution is also very simple, that is, do notstd
Addswap
Functionswap
Defined inWidget
In the namespace:
namespace WidgetStuff { template<typename T> class Widget { ... }; template<typename T> void swap(Widget<T>& a, Widget<T>& b){ a.swap(b); }}
Anywhere in twoWidget
Onswap
C ++ will findWidgetStuff
TheWidget
Parameterswap
.
It seems that Swap of the class only needs to be defined in the same namespace.swap
Function without specialstd::swap
. But! Some people prefer to write directlystd::swap(w1, w2)
, Specialstd::swap
It makes your class more robust.
Because the call is specifiedstd::swap
, Argument-dependent lookup becomes invalid,WidgetStuff::swap
Will not be called.
Speaking of this, you may ask if I want to give priorityWidgetStuff::swap
If not defined, callstd::swap
, How should I write it? Check the Code:
Template <typename T> void doSomething (T & obj1, T & obj2) {using std: swap; // make 'std :: swap 'SWAp (obj1, obj2) is visible in this scope; // now, the compiler will help you select the best swap}
At this time, the C ++ compiler will give priority to calling the specified Tstd::swap
, Followedobj1
TypeT
Corresponding to the namespaceswap
Function.std::swap
.
Best practices
How to Implement Swap? Summary:
- Provides a more efficient common member function without throwing exceptions (for example
Widget::swap
).
- Provide non-member functions in the same namespace of your class (or class template)
swap
To call your member functions.
- If you are writing a class instead of a class template, please turn it special
std::swap
You should also call your member functions.
- Use
using
Enablestd::swap
Visible, and then directly callswap
.
Unless indicated, this blog post is original, reprinted please in the form of a link to indicate the address: http://harttle.com/2015/08/23/effective-cpp-25.html
Copyright Disclaimer: This article is the original article of the blogger. For more information, see the original article link.