Negative tive C ++ Clause 25: consider writing a swap function that does not throw an exception.

Source: Internet
Author: User

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.

If swap's default implementation version is inefficient (some pimpl ):

1. Provide a public swap member function, which should never throw an exception.

2. Provide a non-member swap in The namespace where the class or template is located, and ask him to call the above swap member function.

3. If you are writing a class (instead of a class template), you will be specially crafted for your class STD: swap. He can call the swap member function.

If you call swap, make sure that it contains a using declarative, and then call swap without any namespace modifier.

Member edition swap must not throw an exception.

One of the best applications of swap is to help classes (class templates) provide strong exception security. (Clause 29 provides all details about this) this technology is based on the assumption that the member edition's swap will never throw an exception. When you write a custom version of swap, it not only provides efficient replacement of object values, but also does not throw an exception. Generally, these two swap features are connected, because efficient swaps are almost always based on built-in operations (such as the underlying pointer of the pimpl method ), built-in operations will never throw an exception.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.