Anomaly specifications declaration
It is now a time to explore the unusual support of the C standard run library and Visual C in the header file
l The base class of an abnormal object thrown from the run library.
l An any alternative to the object that violates the abnormal specifications.
l In violation of abnormal specifications, the abnormality declared is called function, as well as hooks ("hook") that increase things on its behavior.
l The function called when the abnormality process is terminated, and the hooks that add things on their behavior.
I have begun to start with the analysis of anomalous specifications and procedures against it. Analysis will be aimed at the topics mentioned above, and some of the millions of usual C abnormalities.
1.1 Abnormal Specification Review
The abnormal specifications declared that the C function declared, and they specified what exceptions can be thrown. For example, functions
Void f1 () throw (int)
You can throw an integer anomaly, and
Void F2 () Throw (char *, e)
You can throw a CHAR * or an E (here the E is a user-defined type) type exception. An empty specification declaration
Void f3 () throw ()
Indicates that the function does not throw an exception, and there is no specifications
Void F4 ()
Indicates that the function can throw anything. Pay attention to grammar
Void f4 () throw (...)
Better than the previous "anything" function, because it is similar to "capturing anything"
Catch (...)
However, recognizing the "throwing anything" function allows those functions written before the abnormal specifications declared.
1.2 violation of abnormal specifications
So far, I have written all: The function may throw out the exceptions described in its abnormal specifications. "May" Some are thin, "must" stronger. "May" indicates that the function can ignore their exception specifications. You may think that the compiler will prohibit this behavior:
Void f () throw () // Promis Not to Throw ...
{
Throw 1; // ... but does anyway - error?
}
But you are wrong. Try with Visual C , you will find that the compiler remains silent, it did not find the compile period error. In fact, in the compiler I have used, there is no newspaper error.
Although this is said, but the abnormal specifications have its rules, the function violates it will suffer serious consequences. Unfortunately, these consequences appear in runtime errors rather than compile. If you want to see, put the above small code in a full program:
Void f () throw ()
{
Throw 1;
}
int main ()
{
f ();
Return 0;
}
What will happen when the program is running? f () throws an INT-type abnormality and violates its contract. You may think this exception will leak into the running library from main (). Based on this assumption, you tend to use a simple TRY block:
#include
Void f () throw ()
{
Throw 1;
}
int main ()
{
Try
{
f ();
}
Catch (int)
{
Printf ("CAUGHT INT / N");
}
Return 0;
}
To capture this exception to prevent it from leaking.
In fact, if you compile and run with Visual C 6, you will get: Caught Int
You once again strange throw () anomalous specification actually do useful things, in addition to adding the size of the source code and looks more pleasant. Your strange feeling will become slow, just think about how much Visual C violates the C standard, only one new problem: Is Visaul C correctly handled the case of violation of abnormal specifications?
1.3 Investigation Description ...
No!
Does this procedure meet the standard? Catch statement should not enter. From the standard (Subclauses 15.5.2 and 18.6.2.2):
l An abnormal specification declares that only the abnormality listed is thrown.
l If the function of the abnormal specification is throws an exception that is not listed, functions
l void unExpected () is called immediately after returning the stack.
l Function UNEXPECTED () will not return ...
When a function attempts to throw an exception listed, an exception handler is called through the UNEXPECTED () function. The default implementation of this exception handler is to call Terminate () to end the program.
After I giving you a short routine, I will show how Visual C is different from the standard.
1.4 Unexpected () Function Guide
UNEXPECTED () function is a function of the standard runtime declaration in header file
Based on my understanding of the standard, the implementation of the UNEXPECTED () function of the runtime is theoretically:
void _default_unexpected_handler_ ()
{
Std :: terminate ();
}
Std :: unnexpected_handler _unexpected_handler =
_default_unexpected_handler;
void unExpected ()
{
_unexpected_handler ();
}
(_Default_unexpected_handler and _unexpected_handler is my fictional name. The implementation of your runtime may use other names, depending on its implementation.)
Std :: unExpected () calls a function to truly process the unmexpected exception. It references this processing function through a hidden pointer (_UNEXPECTED_HANDAL, type std :: undected_handler). The runtime provides a default handler (default_unexpected_handler ()), which calls std :: terminal () to end the program.
Because it is indirectly called by the pointer _unexpected_handler, you can change the built-in call _default_unexpected_handler to call your own handler, as long as the type of handler is compatible with std :: undepected_handler:
TYPEDEF VOID (* unnexpected_handler) ();
Similarly, the processing function must not return to its caller (std :: undected ()). No one stops you from writing a process that will return, but such a process function is not standard compatible, and the result is a sick state of the program's behavior. You can hill your own processing functions through the standard run library. Note that the run library only maintains a process function to process all UNEXPECTEDs; once you call the set_unexpected () function, the run library will no longer remember the previous processing function. (Compared with Atexit (), at least 32 EXIT processing functions can be hung.) To overcome this limit, you either set different processing functions at different times, or make your handle function in different contexts Different behaviors.
1.5 Visual C VS Unexpected
Try this simple example:
#include
#include
#include
Using namespace std;
void my_unexpected_handler ()
{
Printf ("in Unexpected Handler / N);
Abort ();
}
Void throw_unexpected_exception () throw (int)
{
Throw 1L; // Violates Specification
}
int main ()
{
Set_unexpected (my_unexpected_handler);
Throw_unexpected_exception ();
Printf ("This Line Should Never APPEAR / N");
Return 0;
}
Compile and run with a standard compatible compiler, the program results are:
In Unexpected Handler
It may be next to an exception to terminate (because there is a call of Abort ()). But use Visual C to compile and run, the program will throw the "Unhand Exception" dialog. After closing the dialog, the program output:
This Line Should Never Appear
It must be recognized that Visual C does not implement unExpected (). This function is declared in
In fact, Visual C does not even have correctly declared that this theoretical equivalent program can prove:
#include
#include
#include
// using namespace std;
void my_unexpected_handler ()
{
Printf ("in Unexpected Handler / N);
Abort ();
}
Void throw_unexpected_exception () throw (int)
{
Throw 1L; // Violates Specification
}
int main ()
{
Std: set_unexpected (my_unexpected_handler);
Throw_unexpected_exception ();
Printf ("This Line Should Never APPEAR / N");
Return 0;
}
Visual C cannot compile this program. View
I hope that Microsoft can correct these issues in the next version. Before not corrected, when discusses Unexpected (), I suggest you use standard compatible C compilers.
1.6 Maintenance program survival
In the simple example I have shown, the program stopped in my_unexpected_handler (). Sometimes, let the program stop reasonably and correct; but more cases, the program stop is too exciting, especially when UNEXPECTED is indicated, the program is only slight error.
Assume that you want to handle Unexpected anomalies, and recover procedures, just like most of the other "normal" exceptions. Because unExpected () never returns, the program recovery does not seem to be impossible, unless you have seen the standard Subclause 15.5.2:
Unexpected () should not return, but it can be throw (or RE-thROW) an exception. If it throws a new exception, this exception is the abnormal specification declaration allowed, and the behavior of another exception handler is in the place where UNEXPECTED () continues.
Great! If MY_UNEXPECTED_HANDLER () throws an exception allowed, the program can recover from the original violation of the abnormal specifications. In our example, the initial exception specifications stated that the INT type is abnormal. Based on the above saying, if MY_UNEXPECTED_HANDLER throws an int exception, the program will continue.
Based on this speculation, try:
#include
#include
void my_unexpected_handler ()
{
Printf ("in Unexpected Handler / N);
Throw 2; // allowed by Original Specification
// Abort ();
}
Compile operation with standard compatible compiler, program output:
In Unexpected Handler
Program res scheme
And expectations.
Throwing int exceptions and other exceptions are calling chain delivery and capture by the first matching exception handler. In our example, the program controls from my_unexpected_handler () back to main () back to main (), and captures exceptions in Main (). With this method, my_unexpected_handler () turns an exception converter to convert a last "bad" LONG exception to a "good" INT exception.
Conclusion: You can recover the run of the program by converting an unExpected exception for EXPECTED.
1.7 notice
Next time, I will end the discussion of std :: undpected (): reveal the limitations of the omnippected_handler (), explore the remedy for these restrictions, and give the general guidelines for processing UNEXPECTED. I will also start discussing the related content of the run library function std :: terminal ().
Void throw_unexpected_exception () throw (int)
{
Throw 1L; // violates specification}
int main ()
{
Std: set_unexpected (my_unexpected_handler);
Try
{
Throw_unexpected_exception ();
Printf ("This Line Should Never APPEAR / N");
}
Catch (int)
{
Printf ("program resumed / n");
}
Return 0;
}