Objective c ++ Study Notes-cla08: do not let exceptions escape the destructor

Source: Internet
Author: User

Prevent exceptions from leaving destructors
These terms mainly describe how to handle exceptions and how to safely handle exceptions when we write code. Make our code look more perfect.
1. Problem Source
Case 1
C ++ does not prohibit the Destructor from spitting out exceptions, but it does not encourage you to do so. Therefore, when we accidentally write the problematic code. Consider the following code:
C ++ does not prohibit the Destructor from spitting out exceptions, but it does not encourage you to do so. Consider the following code:
Class Widget
{
Public:
~ Widget () {...} // suppose this may spit out an exception
};
Void dosomething ()
{
Vector <Widget> v;
} // V is automatically destroyed here

When a vector is destroyed, it has the responsibility to destroy all its contained Widgets. Suppose v contains ten Widgets, and an exception is thrown during the first element of the analysis. The other nine widgets should still be destroyed, so v should call their respective destructor. However, during those calls, the second widget destructor throws an exception. Now there are two exceptions simultaneously, which is too much for c ++.
If two exceptions exist at the same time, if the program is not executed, it will lead to unclear behavior. In this example, ambiguous behaviors will occur. The same situation also occurs when any other container of the standard library or any container of TR1 or even array is used. The container or array is not a necessary condition for the trouble. As long as the Destructor spit out an exception, even if it is not a container or arrays, the program may end prematurely or have ambiguous behavior. So that c ++ does not like the destructor to spit out exceptions!

Case 2

This is easy to understand, but what if your destructor must execute an action that may throw an exception upon failure? For example, assume that you use a class to connect to the database:
Class DBConnection {
Public:
...
Static DBConnection create (); // This function returns the DBConnection object. to simplify the temporary parameters.
Void close (); // close online. If the connection fails, an exception is thrown.
};

2. Solutions

To ensure that the customer does not forget to call close () on the DBConnection object, a reasonable idea is to create a class for managing DBConection resources and call close in its destructor. This type of classes for resource management is discussed in Chapter 3rd. Here, we only need to consider the appearance of their destructor:

Class DBConn {// This class is used to manage DBConnection objects
Public:
...
~ DBConn () // make sure that the database connection is always closed
{
Db. close ();
}
Private:
DBConnection db;
};
This allows the customer to write such code:

{// Open a Block ).
DBConn dbc (DBConnection: create (); // create a DBConnection object and hand it over to the DBConn object for management. Use the DBConnection object through the DBConn interface.
... // At the block end point, the DBConn object is destroyed, and therefore close is automatically called for the DBConnection object.
}

As long as close is successfully called, everything is fine. However, if this call causes an exception, the DBConn destructor will send the exception, that is, allow it to leave the destructor. This can cause problems, because it throws out uncontrollable troubles.
This problem can be avoided in two ways. DBConn destructor can be:
Solution 1. If close throws an exception, terminate the program. It is usually completed by calling abort:
DBConn ::~ DBconn ()
{
Try {db. close ();}
Catch (...)
{
Abort ();
}
}
If the program fails to be executed after an "error occurred during the Destructor", "Force terminate the program" is a reasonable option, after all, it can prevent exceptions from spreading from the Destructor (which will lead to ambiguous behavior ). That is to say, calling abort can preemptively produce "ambiguous behaviors.

Solution 2: swallow the exception caused by calling close:
DBConn ::~ DBConn
{
Try {db. close ();}
Catch (...)
{
// Create a running record and write down the call to close failed!
}
}

3. Further solutions
In general, it is a bad idea to swallow an exception because it suppresses the important information of "some actions failed! However, sometimes it is better to swallow exceptions than to "End the program rashly" or "risks brought about by ambiguous behaviors. To make this a viable solution, the program must be able to continue reliably, even after an error is encountered and ignored.

These methods are not very good. A better strategy is to redesign the DBConn interface so that its customers have the opportunity to respond to possible problems. For example, DBConn itself can provide a close function, giving the customer a chance to handle "exceptions caused by this operation ".
Move the responsibility for calling close from the DBConn destructor to the DBConn client. You may think it violates the advice of making the interface Easy to use correctly. In fact, this foul name is not true. If an operation may throw an exception when it fails, and another exception must be handled, the exception must be a function other than the self-destructor. It is dangerous to spit out exceptions in the destructor, which may lead to the risk of "premature termination of the program" or "ambiguous behavior.

Class DBConn {
Public:
...
Void close () // new function for the customer
{
Db. close ();
Closed = true;
}
~ DBConn ()
{
If (! Closed ){
Try {// close the connection (if the customer does not)
Db. close ();
}
Catch (...) {// If the stop action fails, record it and end the program or swallow an exception.
Make a running record and write down the call to close failed;
...
}
}
}
Private:
DBConnection db;
Bool closed;
};
In this example, the customer's own call to close will not impose a burden on them, and 20 will give them a chance to handle errors, otherwise they will not have a chance to respond accordingly. If they do not think this opportunity is useful (maybe they believe there will be no errors), they may ignore it and rely on the DBConn destructor to call close. If a real error occurs -- if close does throw an exception -- and DBConn swallowed the exception or ended the program, the customer had no position to complain. After all, they had the opportunity to handle the problem first, and they chose to give up.

Remember:


1. do not spit out exceptions. If a function called by the Destructor may throw an exception, the Destructor should capture any exceptions and swallow them (not spread) or terminate the program.


2. If the customer needs to respond to exceptions thrown during the running of an operation function, the class should provide a common function (not in the destructor) to execute this operation.

Author's "wallwind's column"
 

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.