A
By default, the swap action is completed by the swap algorithm provided by the standard library:
Namespace Std { template<typename t> void Swap (t& A, t& b) { T temp (a); A = b; b = temp; } }
This function is at the heart of exception-safe programming and is a common mechanism for dealing with the possibility of self-assignment.
However, for some types, these copying actions are not necessary: the basic one is "pointing to an object with a pointer, containing the real data" type. "Pimpl gimmick" (pointer to implementation abbreviation)
<span style= "color: #333333;" ><span style= "Font-family:verdana, Arial, Helvetica, sans-serif;font-size:12px;" >class Widgetimpl {private: int A, b, C; Std::vector<double> v; }; Class Widget {public: widget (const widget& RHS); widget& operator= (const widget& RHS) { *pimpl = * (Rhs.pimpl); } private: widgetimpl* Pimpl;}; </span></span>
The value of the two Widget object to displace. The only thing to do is replace the Pimpl pointer, which is not known by the default swap algorithm. Not only copy 3 widgets but also replicate 3 Widgetimpl objects. Very inefficient!
The workaround:
We were able to make the widget declare a swap public member function to do the real replacement work, and then Std::swap. Make him call this member function:
<span style= "color: #333333;" ><span style= "Font-family:verdana, Arial, Helvetica, Sans-serif;" >class Widget {public: widget (const widget& RHS); widget& operator= (const widget& RHS) { *pimpl = * (Rhs.pimpl); } void Swap (widget& other) { using Std::swap; Swap (Pimpl, Other.pimpl); } Private: widgetimpl* Pimpl;}; </span></span><pre name= "code" class= "CPP" style= "LINE-HEIGHT:19PX; text-align:justify; " >class Widgetimpl {private: int A, b, C;
namespace std{template<> void swap<widget> (widget& A, widget& b) {a.swap (b);}}
This approach is not only compiled, but also consistent with STL containers. Since all STL containers also provide the public swap member function and the Std::swap version number (to invoke the former).
(ii)
If the widgets and Widgetimpl are class templates instead of classes:
<span style= "color: #333333;" ><span style= "Font-family:verdana, Arial, Helvetica, Sans-serif;" >template <typename t>class widgetimpl{...}; Template <typename t>class widget{...}; </span></span>
The so-called "partially specialize":C + + agrees to "part-specific" the class template. But do not agree to "partial specificity" of template functions。
The following definition is wrong (the widget class in the example above is written as a template class):
namespace Std{template<typename t>void swap<widget<t>> (widget<t>& A, Widget<T> & B) {//error. Not legal!A.swap (b);}}
even adding an overloaded version number does not work. Because the standard namespace is a special namespace, customers can fully specialized templates inside, but cannot add new templates (including class templates and function templates) to the standard namespace. So the following methods do not work!
namespace Std{template<typename t>void Swap (widget<t>& A, widget<t>& b) {//attempt to reload, illegal. A.swap (b);}}
In general, there is no problem with overloading the function template, but STD is a special namespace. Management is also more special. Customers are able to fully templates within the Std. However, it is not possible to add new templates (or class or function or anything else) to Std. In fact, programs that cross the red line are almost still compiled and run, but their behavior is not clearly defined. Sodon't join any new things into Std..
Workaround:
To provide a more efficient template-specific version number. We also declare a non-member swap but no longer a Std::swap version number or an overloaded version number:
namespace Widgetstuff { template<typename t> class widget{...}; Template<typename t> void Swap (widget<t>& A, widget<t>& b) { a.swap (b); }}
Now. Regardless of where the code assumes the intention to displace two Widget objects, calling swap,c++ 's name lookup rule is called "Argument-dependent lookup" to find the exclusive version number within the Widgetstuff.
Three
Template<typename t> void DoSomething (t& obj1, t& obj2) { swap (obj1, obj2);}
which swap should I use on top? Is it the generic version number of the STD, or is it a specific version number that may exist? You want to call the T exclusive version number. and calls the generalized version number within STD If the version number does not exist. Here's what you want to happen:
Template<typename t> void DoSomething (t& obj1, t& obj2) { using Std::swap; Make Std::swap swap available within this function (obj1, obj2);}
The name lookup rule for C + + ensures that no specific swap is found within the namespace of the global scope or T. Assuming that T is a widget and is in the namespace Widgetstuff, the compiler will find the swap within the widgetstuff.
Suppose there is no exclusive swap exists. The compiler is using the swap in STD, but even so. The compiler is also more like the Std::swap Special version number of T, rather than the generic template.
Summarize:
(1) Assume that the default implementation code for Swap provides an acceptable efficiency for your class or class template. Then we don't need to do anything extra.
(2) Assuming the swap default implementation is inefficient (some kind of pimpl), then we'll do it like this:
1. Provide a public swap member function. This function should never throw an exception.
2. Provide a non-member swap within the namespace of the class or template, and make him call the swap member function above.
3. Suppose you are writing a class (rather than a class template) for your class-specific std::swap. And make him call the swap member function.
Suppose you call swap and make sure that you include a using declaration so that Std::swap is visible within your function, and then no matter what the namespace modifier, the naked call to swap is made.
one of the best applications for swap is to help classes (class templates) provide strong exception security. (clause 29 provides full details of this) this technique is based on a if: Member version of swap never throws an exception. When you write a custom version number of swap, it provides more than a way to efficiently displace object values without throwing an exception. In general, these two swap characteristics are linked, since efficient swaps almost always based on operations on built-in types (such as the underlying pointer of the PIMPL technique), and operations on built-in types never throw exceptions.
Please remember:
(1) When Std::swap is not efficient for your type, provide a swap member function and make sure that the function does not throw an exception.
(2) Suppose you provide a member swap, you should also provide a non-member swap to invoke the former. For classes (not template), please also special std::swap.
(3) When you call swap, you should use the using declaration for Std::swap, and then call swap without any namespace qualification adornments.
(4) STD templates for "User Defined type" is good, but never try to add something new to Std.
Effective C + +: Clause 25: Consider writing a swap function that does not throw an exception