I l @ ve RuBoard |
Recap: Evaluation Orders and Disorders
Ignoring threads, which are not mentioned in the C++ standard, the answer to the first question hinges on the following basic rules:
Given those rules, let's see what happens in our opening examples: // Example 20-1(a) // f( expr1, expr2 ); In Example 20-1(a), all we can say is that both expr1 and expr2 must be evaluated before f() is called. That's it. The compiler may choose to perform the evaluation of expr1 before, after, or interleaved with the evaluation of expr2 . There are enough people who find this surprising that it comes up as a regular question on the newsgroups, but it's just a direct result of the C and C++ rules about sequence points. // Example 20-1(b) // f( g( expr1 ), h( expr2 ) ); In Example 20-1(b), the functions and expressions may be evaluated in any order that respects the following rules:
That's it. For example, this means that any one or more of the following are possible:
Some Function Call Exception Safety Problems
// Example 20-2 // // In some header file: void f( T1*, T2* ); // In some implementation file: f( new T1, new T2 ); Does this code have any potential exception safety problems? Explain . Yes, there are several potential exception safety problems. Brief recap: An expression such as new T1 is called, simply enough, a new-expression. Recall what a new-expression really does (ignoring in-place and array forms for simplicity, because they're not very relevant here):
So each new-expression is essentially a series of two function calls: one call to operator new() (either the global one, or one provided by the type of the object being created), and then a call to the constructor. For Example 20-1, consider what happens if the compiler decides to generate code as follows :
The problem is this: If either step 3 or step 4 fails because of an exception, the C++ standard does not require that the T1 object be destroyed and its memory deallocated. This is a classic memory leak, and clearly Not a Good Thing. Another possible sequence of events is the following:
This sequence has not one, but two exception safety problems with different effects:
"Hmm," you might wonder , "then why does this exception safety loophole exist at all? Why doesn't the standard just prevent the problem by requiring compilers to Do the Right Thing when it comes to cleanup?" Following the spirit of C in the matter of efficiency, the C++ standard allows the compiler some latitude with the order of evaluation of expressions, because this allows the compiler to perform optimizations that might not otherwise be possible. To permit this, the expression evaluation rules are specified in a way that is not exception-safe, so if you want to write exception-safe code you need to know about, and avoid, these cases. Fortunately, you can do just that and prevent this problem. Perhaps a managed pointer like auto_ptr could help? We'll see the answer in Item 21. |
I l @ ve RuBoard |