More Effective C ++ Terms 13

zhaozj2021-02-08  309

Terms 13: Capture exceptions by reference (Reference)

When you write a Catch clause, you must make sure that the exception is passed to the Catch clause. You can have three options: Like the function passing the parameters, through the pointer, pass the value or by reference (by reference).

We first discuss the Catch by Pointer. Passing an abnormality from the Throw is a slow process, in theory, the implementation of this method is the highest efficiency for this process. Because when the abnormal information is transmitted, only the method of throwing an abnormality by the pointer (see Terms 12), for example:

Class Exception {...}; // from standard C library (STL)

/ / Abnormal class level

// (see Terms 12)

void somefunction ()

{

Static Exception EX; // Abnormal Object

...

Throw & ex; // Throw a pointer, point to EX

...

}

Void Dosomething ()

{

Try {

SomeFunction (); // Throw an Exception *

}

Catch (Exception * EX) {// Capture Exception *;

... // No object is copied

}

}

This looks very good, but the actual situation is not the case. In order to allow the program to run normally, the programmer must ensure that the object can continue to survive when the program control leaves the function of throwing the pointer. Both global and static objects can do this, but programmers can easily forget this constraint. If so, they will write code this:

void somefunction ()

{

Exception ex; // local abnormal object;

/ / When the exit function is time to survive

// This object will be released.

...

Throw & ex; // throw a pointer, pointing

... // Objects that have been released

}

This is bad, because the pointer to which this exception is accepted, the object to which it points to it has no longer exists.

Another way to throw a pointer is to create a heap object: NEW Object:

void somefunction ()

{

...

Throw new exception; // throw a pointer, point to a heap

... // Established object (hope

} // operator new - see Terms 8-

// Don't throw one more

// Abnormal!)

This avoids capturing a problem that points to the pointer to which has been released, but the author of the CatCH clause is facing a headache: Do they delete the pointer they accept? If it is an exception object established in the heap, then they must delete it, otherwise it will cause resource leakage. If it is not established in the heap, they absolutely can't delete it, otherwise the behavior of the program will not be predictable. What should I do? This is impossible to know. Some Clients may pass the address of the global or static object, and others may transfer the address of the exception object established in the stack. The pointer is captured by the pointer, will encounter a Hamlet puzzle: Is it deleted or not deleted? This is a problem that is difficult to answer. So you'd better avoid it.

Moreover, it is not conform to the C language itself by pointer. Four standards - Bad_alloc (when Operator New (see Terms 8) is not assigned enough memory), BAD_CAST (when Dynamic_CAST fails), BAD_TYPEID ( When Dynamic_CAST is operated for empty pointers, it is thrown) and BAD_EXCEPTION (for unExpected exception; see Terms 14) - do not point to the object's pointer, so you must pass values ​​or reference to capture them.

The above problems can be solved by value capture exception (Catch-by-value), such as the problem of abnormal object deletion, and a problem using standard exception type. However, when they are thrown out, the system will copy twice (see Terms 12). And it generates SLICING ProBLEM, that is, the abnormal object of the classification is used as the base class anomaly object capture, the derived type behavior is cut off (SLICED OFF). Such SLICED objects are actually a base class object: they are not derived by data members, and when their virtual functions are called, the system parsed is the function of the base class object. (When an object is passed to a function through a pass value, it will also happen - see Effective C Terms 22). For example, the following program uses an exception class hierarchy of extended self-standard anomaly:

Class Exception {// As above, this is

Public: // A standard anomaly class

Virtual const char * what () throw ();

// Return the short description of the abnormality.

... // ((at the end of the function declaration)

// "throw ()",

}; // Information about it

// See Terms 14)

Class runtime_error: // also from standard C anomaly class

PUBLIC EXCEPTION {...};

Class Validation_ERROR: // Customer Add a class

Public runtime_error {

PUBLIC:

Virtual const char * what () throw ();

// Reconfers in an exception class

... // Virtual Function

}; //

Void someFunction () // throw a validation {// exception

...

IF (a Validation test failed) {

Throw validation_error ();

}

...

}

Void Dosomething ()

{

Try {

SomeFunction (); // Throw validation

} // abnormal

Catch (Exception EX) {// Capture all standard anomaly classes

/ / Or its derived class

CERR << EX.WHAT (); // calls Exception :: What (),

... // instead of validation_error :: what ()

}

}

Calling is the base class of the base class, even if the abnormality object thrus is the Validation_ERROR and the Validation_Error type, they have redefined the virtual function. This SLICING is never expected.

The last remaining method is to capture the capture exception (Catch-by-reference). You can avoid all of the above problems by citing capturing exceptions. This method does not have object deletions by pointer, and it can also capture standard exception types. Nor like capturing exceptions via values, this method does not have SLICING ProBLEM, and the abnormal object is only copied once.

We rewrote the last example by reference to capturing exceptions, as shown below:

Void somefunction () // This function has not changed

{

...

IF (a Validation test failed) {

Throw validation_error ();

}

...

}

Void Dosomething ()

{

Try {

SomeFunction (); // has no change

}

Catch (Exception & EX) {// Here we pass the cited capture exception

// Capture by replacing the original via value

CERR << EX.WHAT (); // is now called

// Validation_ERROR :: What (),

... // instead of Exception :: What ()

}

}

There is no change in Throw, just change the Catch clause, give it a & symbol. However, this tiny change can cause huge changes, because the virtual function in the CatCH block can work as we wish: The Validation_ERRO function called is the function we redefined.

If you can avoid all the problems described above by reference, you can avoid the above problems, you don't worry about whether you delete an exception object; avoid the SLICING anomaly object; can capture standard exception types; reduce exception objects need to be copied Number of. So what are you waiting for? Catch Exceptions By Reference!

转载请注明原文地址:https://www.9cbs.com/read-966.html

New Post(0)