By default, swap actions can be completed by the swap algorithm provided by the Standard Library:
Namespace STD {
Template <typename T>
Void swap (T & A, T & B)
{
T temp ();
A = B;
B = temp;
}
}
But for some types, These replication actions are unnecessary: The main type is "pointing to an object with a pointer containing real data. Most of them are pimpl techniques (the abbreviation of pointer to implementation ). Design widget class:
Class widgetimpl
{
Public:
...
Protected:
PRIVATE:
Int A, B, C;
STD: vector <double> V;
...
};
Class widget
{
Public:
Widget (const widget & RHs );
Widget & operator = (const widget & RHs)
{
...
* Pimpl = * (RHS. pimpl );
}
Protected:
PRIVATE:
Widgetimpl * pimpl;
};
To replace the values of two widgets, replace the pimpl pointer. The default swap algorithm does not know this. Not only are three widgets copied, but also three widgetimpl objects. Very inefficient!
We can make STD: swap all special:
Namespace STD {
Template <>
Void swap <widget> (widget & A, widget & B)
{
Swap (A. pimpl, B. pimpl); // The Private member variable cannot be accessed through compilation.
}
}
Although this special version can be declared as friend, but this is not the same as the previous rule, we can make the widget declare a swap public member function for real replacement, and then STD:: swap special, so that he can call this member function:
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 );
}
Protected:
PRIVATE:
Widgetimpl * pimpl;
};
Namespace STD {
Template <>
Void swap <widget> (widget & A, widget & B)
{
A. Swap (B );
}
}
Assume that the widget and widgetimpl are both Class templates and not classes:
Template <typename T>
Class widgetimpl {...};
Template <typename T>
Class widget {...};
In the special STD: swap:
Namespace STD {
Template <typename T>
Void swap <widget <t> (widget <t> & A, widget <t> & B) // wrong! Invalid!
{
A. Swap (B );
}
}
We tried to optimize a function template, but in C ++, only the class templates can be converted to a specific function template. This code should not be compiled (although some compilers mistakenly accept it ).
When you want to optimize a function template, the usual practice is to simply add an overloaded version for it:
Namespace STD {
Template <typename T>
Void swap (widget <t> & A, widget <t> & B) // note that "No after swap <>"
{
A. Swap (B );
}
}
In general, there is no problem with overloading function templates, but STD is a special namespace and management is quite special. The customer can specialize in templates within STD, but cannot add new templates (or class or function or anything else) to STD. In fact, programs that span the red line can still be compiled and executed, but their behavior is not clearly defined. So do not add any new things to STD.
No template-specific versions of higher education institutions are provided. We still declare a non-member swap, but it is no longer a special version of STD: swap or an overloaded version:
Namespace widgetstuff {
Template <typename T>
Class widget {...};
Template <typename T>
Void swap (widget <t> & A, widget <t> & B)
{
A. Swap (B );
}
}
Now, if any code in any location is intended to replace two widget objects, swap is called, the Name Lookup rule of C ++ is called "argument-dependent lookup" and finds the exclusive version in widgetstuff.
Template <typename T>
Void dosomething (T & obj1, T & obj2)
{
...
Swap (obj1, obj2 );
...
}
Which swap should I use? Is the general version of STD or a special version that may exist? You want to call the dedicated version T and call the general version in STD if the version does not exist. The following is what you want to do:
Template <typename T>
Void dosomething (T & obj1, T & obj2)
{
Using STD: swap; // make STD: swap available in this function
...
Swap (obj1, obj2 );
...
}
C ++'s Name Lookup rule (Name Lookup rules) ensures that any T exclusive swap within the global scope or the namespace where T is located will be found. If T is a widget and is located in the namespace widgetstuff, the compiler will find the SWAp in widgetstuff. If the T exclusive swap exists, the compiler uses the SWAp in STD. However, even so, the compiler prefers the T exclusive special version of STD: swap, instead of the general template.
STD: swap (obj1, obj2); // This is the incorrect swap call method.
This forces the compiler to recognize only swap in STD (including any of its template features), so it no longer calls a more appropriate T-exclusive version defined elsewhere. That is why "your classes fully features STD: swap": the Exclusive type of swap implementation version can be used by these lost code.
If the default implementation code of swap provides acceptable efficiency for your classes or class template, you do not need to do anything else.
Member edition swap must not throw an exception.