1. Microsoft's exception handling in the implementation version of
Last time, I explained the abnormal behavior in the 12 full-organized functions declared in the standard running library header file
In Visual C 5, the standard running library header file
Namespace STD
{
Class Bad_alloc;
Struct NothRow_t;
Extern NothRow_t const nothrow;
}
Void * Operator new (SIZE_T) THROW (std :: bad_alloc);
Void Operator Delete (Void *) throw ();
Void * Operator new (SIZE_T, VOID *);
Void * Operator new (size_t, std :: nothrow_t constatabase);
Compared with the standards required by the standards described in the fifth part, Microsoft's
l All (three) forms of Operator New []
l All (three) forms of Operator Delete []
l Placement Operator Delete (void *, void *)
l Placement Operator Delete (void *, std :: nothrow_t const)
And, although the running library declares that Operator New throws std :: Bad_alloc, the behavior of functions does not meet the standard.
If you use the Visaul C 6,
1.1 array
Visual C does not define the version of Operator New [] and Operator delete [] in the implementation of the standard runtime. Fortunately, you can build your own version:
#include
Void * Operator new (size_t)
{
Printf ("Operator new / n");
Return 0;
}
Void Operator Delete (void *)
{
Printf ("Operator Delete / N");
}
Void * Operator new [] (size_t)
{
Printf ("Operator New [] / n");
Return 0;
}
Void Operator Delete [] (void *)
{
Printf ("Operator Delete [] / N");
}
int main ()
{
INT * P;
P = new int;
Delete P;
P = new int [10];
Delete [] P;
}
/ * WHEN Run SHOULD YIELD
Operator new
Operator delete
Operator new []
Operator delete []
* /
Why is Visual C standard runtime lack of these functions? I can't affirm it, guess is "backward compatibility".
Operator new [] and operator delete [] joins the C standard late, and many years compilers do not support it, all compilers that support allocated user-defined objects define Operator New and Operator Delete, and even allocate arrays Objects will also call them. If a compiler that does not support Operator New [] and Operator Delete [] begins to support them, the user-defined global Operator New and Operator delete functions will no longer be called when an array object is allocated. The program is still compiled and running, but behavior has changed. The programmer can't even know what to change, because the compiler does not report any fault.
1.2 silent change
These silent changes have been given to the compiler (such as Microsoft). You know, C standard has developed for nearly 10 years. During this period, the seller's seller tracking standard changes to ensure the greatest extent of the final version. At the same time, users rely on the currently available language characteristics, even if they cannot be ensured in a standardized process.
If a clear change in the standard has caused a quiet change in the behavior of the programs that meet the criteria, there are three choices for the seller of the compiler:
1. Adhere to the old behavior, ignore the code that meets the new standard
2. Change to new behavior, ignore the code of the old standard
3. Let users specify the behavior they want
The standard runtime here provides Operator New [] and Operator Delete [], MicrSoft selected 1. I hope they choose 3, and do not meet the standards and all other Visual C . They can determine the user's decision through the #pragmas, compile options, or environment variables.
Visual C has long passed the selection 3 through the compilation switch such as / za, but this switch has an unapproved behavior: it turns off some standard compatible features, and then opens another. I expect (thinking about most people expects) is a perfect adjustment method to open and close standard compatible features!
(In this Operator New [] and Operator delete [], I recommend that you start using container classes (such as vector) instead of array, but this is another column.)
1.3 abnormal specifications declaration
Microsoft's
Void * Operator new (std :: size_t) throw (std :: bad_alloc);
You can define your own Operator New version to overwrite the version of the running library, you may be written:
Void * Operator new (std :: size_t size) throw (std :: bad_alloc)
{
Void * p = null;
// ... try to allocate '* p' ...
IF (p == NULL)
THROW std :: bad_alloc ();
Return P;
}
If you save the above functions, compile with the default option, Visual C will not report an error. However, if you set the warning level to 4, then compile, you will encounter this information:
WARNING C4290: C Exception Specification Ignored
So good, if your own abnormal specifications declares that you can't work, affirm that the version of the running library cannot be. Keep a warning level 4, then compile: #include
We already know that it declares a function of the same exceptional specifications as our program.
Strange, strange! The compiler has no warning, even at level 4! Does this mean that there is a strange attribute of the running library? No, it tries that MICORSOFT spoofing behavior:
l
l
l Xstddef contains another non-header file Yvals.h.
l Yvals.h includes instruction #pragma Warning (Disable: 4290).
l #pragma closed a warning of a specific level 4, and we see it in your code.
Conclusion: Visual C is declared in compile time checking the abnormal specifications, but it is ignored in the running period. You can add an exception declaration (such as throw (std :: bad_alloc)), the compiler will correctly analyze them, but there is no effect at the runtime, just like it is not written.
1.4 how
In the third part of this column, I talked about the form of abnormal specifications, but did not explain its behavior and effect. Visual C has given me an excellent opportunity to explain them in an exceptional standard.
Abnormal specifications are part of the function and its caller contract. It fully enumerates all the exceptions that the function may thrown. (Specifications in standards, known as function "Allow" specific exceptions.)
In other words, the function is not allowed (promised to throw out) any other abnormality in the declaration. If there is a declaration but empty, the function does not allow any exceptions at all; the function allows any exception if there is no exception specification.
Unless the function and the consolidation between the calling is mandatory, it is not worthwhile to write. So you may think that the compiler should make sure the function does not lie when compiling:
Void f () throw () // 'f' Promis to throw no exception ...
{
Throw 1; // ... yet it throws one annily!
}
Surprisingly, it compiled in Visual C .
Don't think Visual C is disease, this example can be compiled with any compatible C compiler. I am from the standard (SUB CLAUSE 15.4P10):
The implementation version of C should not reject an expression, just because it throws or may throw an exception that its associated function is not allowed. E.g:
Extern void f () throw (x, y);
Void g () throw (x)
{
f (); // ok
}
Calling F () statements are properly compiled, even if f () may throw a G () not allowed exception Y when the call is called.
Is it some special? So good, if the compiler does not force this contract, what will happen?
1.5 runtime system
If the function throws an exception that it does not throw, the runtime system calls the standard run library function UNEXPECTED (). The default unExpected () implementation of the run library is to call Terminate () to end the function. You can call the set_unexpected () function to install the new Unexpected () handle to overwrite its default behavior. This is just theory. But as the Visual C warning is impressed by the previous Visual C , it ignores the abnormal specifications. Therefore, the Visual C runtime system does not call UNEXPECTED () functions, when a function violates its commitment.
To try the behavior of your favorite compiler, compile and run the following applet:
#include
#include
Using namespace std;
void my_unexpected_handler ()
{
Throw bad_exception ();
}
Void promise_breaker () throws ()
{
Throw 1;
}
int main ()
{
Set_unexpected (my_unexpected_handler);
Try
{
Promise_breaker ();
}
Catch (Bad_Exception &)
{
Printf ("busted!");
}
Catch (...)
{
Printf ("escaped!");
}
Return 0;
}
If the program output is:
Busted!
The runtime system completely captures the behavior of violation of abnormal specifications. Conversely, if the output is:
Escaped!
The runtime system does not capture a behavior that violates the abnormal specifications.
In this program, I installed my_unexepected_handler () to overwrite the default unExpected () handler of the running library. This custom handler throws an exception of a std :: bad_exception type. This type has special properties: If the unExpected () exception handler throws this type, this exception can be captured (outside), and the program will continue to run without terminating. In the effect, this Bad_Exception object replaces the original throw object and spreads outward.
This is assumed that the compiler correctly detected unExpected exceptions, in Visual C , MY_UNEXPECTED_HANDLER () did not call, the original INT type exception thrown, and violated the commitment.
1.6 Simulation Abnormal Specification State
If you are willing to have some indecent, you can simulate an abnormal specifications under Visual C . Consider the behavior of this function:
Void f () throw (char, int, long)
{
// ... Whatver
}
What happens when it happened?
l If f () has no exception, it returns normally.
l If f () has a permitted exception, it is abnormally transmitted to F ().
l If f () has an exception of other (not allowed), the runtime system calls the UNEXPECTED () function.
To implement this behavior under Visual C , change the function to:
Void f () throw (char, int, long)
{
Try
{
// ... Whatver
}
Catch (char)
{
Throw;
}
Catch (int)
{
Throw;
}
Catch (long)
{
Throw;
}
Catch (...)
{
Unexpected ();
}
Visual C once started to properly support the abnormal specification, its internal code is inevitably present like I am here. This means that the abnormal specifications declares that there will be some costs like the TRY / CATCH block, just like me in the fourth part.
Therefore, you should use an exceptional specifications well, just like you use other exception components. At any time, you see an exception specification declaration, you should translate them into the Try / Catch queue in your brain to properly understand the relevant price.
1.7 notice
Discussion of Placement Delete To wait until next time. More general policies will continue to be discussed to prevent your design.