Remember:
★ When STD::SWAP is not efficient for your type, provide a Swap member function and determine that it does not throw an exception
★ If you provide a member swap, you should also provide a non-member swap to invoke the former. For classes (not templates), please also special Std::swap
★ You should use the using declaration for std::swap when calling swap, and then call swap without any "namespace qualification adornments"
★ STD Templates for "User Defined type" is good, but don't try to add something new to STD in STD
--------------------------------------------------------------------------------------------
The background of the swap function:
It was originally part of the STL, and then became the spine of unusually safe programming , and a common mechanism for dealing with the possibility of self-assignment (Copy-and-swap technology) .
Example:
classWidget { Public: Widgets (ConstWidgets &RHS); Widgets&operator=(ConstWidgets &RHS) { //Copy widget copies its Widgetimpl objects in season ... *pimpl = *(Ths.pimpl); ... } ... Private: Widgetimpl*Pimpl;};
The Widgetimpl classes are as follows:
classWidgetimpl { Public: ... Private: intA, B, C; Std::vector<Double> v;//There may be a lot of data, which means that replication takes a long time};
To displace two Widget object values, just displace their pimpl pointer, but the STL default swap does not know this, it not only duplicates three widgets, but also replicates three Widgetimpl objects, very inefficient!!!
Procedure One ( compilation error ):
namespace std { template<> // This is std::swap for T is Widget's special version void swap< Widget> (widget &a, widgets &b) { swap (A.pimpl, B.pimpl); // Just need to displace the pointer. }}
Template<> says it is a full-std::swap version of the (not able to change anything within the Std namespace, but it can be customized for standard templates, making it his own classes, As the widget for this example, the code above is doing this). The above code is problematic because Pimpl is private, ∴swap (A.pimpl, B.PIMPL); Statement error
procedure two (for the class the case):
classWidget { Public: ... voidSwap (Widget &other) {//Add the Swap member function within the widget usingStd::swap;//This statement is necessarySwap (Pimpl, Other.pimpl);//the permutation is the pointer } ...};namespaceSTD {Template<>//revised STD::SWAP-specific version voidSwap<widget> (widget &a, Widgets &b) {a.swap (b);//to displace a widget, call its swap member function }}
This is possible, and also consistent with the STL container, ∵ All STL containers also have public swap member functions and STD::SWAP versions (to invoke the former).
Procedure three ( compilation error ):
This is possible, but in the case of widgets and Widgetimpl, what if the widgets and Widgetimpl are all class template ?
Template<typename t>//now becomes class template
Class Widgetimpl {};
Template<typename t>//now becomes class template
Class Widget {};
Putting swap members in the widget is the same as doing two, but you'll encounter problems when you std::swap :
namespace std { template<typename t> // This is biased void// Error! A.swap (b); }}
This so-called special code does not compile , ∵ we try to partial a function template (Std::swap), but C + + only allows the class template to be biased, not function The template is doing this.
Procedure four: Solution of the procedure three
Declare a non-mem. Swap lets it call mem. Swap, but no longer put that non-mem. Swap is declared as a special version of Std::swap.
namespace Widgetstuff { ... // templated Widgetimpl and so on. Template<typename t> class Widget {...}; // Ibid, with swap member functions ... Template// write a non-member alone!! Don't be special! void// Note this is not a STD space A.swap (b); }}
Summarize:
A special version of the default Swap,member swap,non-member Swap,std::swap is now discussed.
first , if the default implementation code for Swap provides an acceptable efficiency for your class or class template, there is no need to do anything extra;
second , if the swap default implementation is inefficient, try to do the following:
1. Provide a public swap member function, and the function should never throw an exception;
2. Provide a non-member swap within the namespace of your class or template and make it invoke the Swap member function above; ( procedure four )
3. If you are writing a class (rather than a class template), Std::swap your class and make it call your swap member. ( procedure two )
finally , if you call swap, make sure that you include a using declaration so that Std::swap is visible within your function, and then make a naked call to swap without adding any namespace modifiers. ( practice two or four all have!!!) )
The last point: the member version of Swap (the swap function written in the procedure two Widget class) must never throw an exception!!!
EC Reading Notes Series 13: clause 25 Consider writing a swap function that does not throw an exception