Re: Handle C++ exception and structured exception together
Alf P. Steinbach wrote:
I think it's as concrete as can be described with words, no hinting.
Double destruction example would just be example of destroying twice,
which is easy to do when using manual destruction instead of RAII,
especially in code where that destruction has to be redundantly repeated
(as is the case with MFC exception handler code).
Memory leak + disaster example code:
void throwX( char const s[] ) { throw std::runtime_error( s ); }
struct Base()
{
virtual ~Base() {}
virtual void foo() = 0;
void bar()
{
try { foo(); } catch( ... ) { throwX( "Base::bar()" ); }
}
};
struct SillyDerived: Base
{
void foo() { int* p = 0; *p = 666; }
};
Now with general SEH -> C++ exception translation enabled, and that SEH
nullpointer exception translated to a C++ throw of pointer to
dynamically allocated object, a call to bar() leaks memory, and much
worse, in the general case where a nullpointer exception indicates
something gone horribly awry, is likely to leave the program in an
unstable state (memory corruption, invalid assumptions) => disaster.
I agree this example won't work.. but why would anybody use catch(...)
for structured exception if the point is to catch CseException or
CException?
See, my understanding of the idea of the article is this:
1. Someone has a WIN32 C library that can throw SHE (or, also, WIN32
itself can do it) and wants to expose these facilities from his C++
library. Say, that C WIN32 C library has a function
void cf(); /* can "throw" SHE */
2. That someone writes a C++ library, including the function, say:
void cppf() throw(CseException *); // I know MSVC++ does not really
// support throw(), not in 2005, anyway, but let's pretend it does..
// maybe it does 2008 or will later.
// And anyway, the interface is useful just
// to show that the function can throw CseException
The library's initialization code will set up the function translating
SHE to C++ exception
3. Then, any sensible programmer who uses the C++ library would write
the client code along these lines:
try {
....
cppf(); // maybe indirectly
....
} catch(CseException *exPtr) {
... // process exception
// Any person familiar with MFC "style" of exception
// pointers ownership,
// will manage the exPtr life style accordingly
}
It is certainly more error prone than RAII would be; on the other hand,
RAII is a very useful but not the only useful way of resource
management.. otherwise why would we need shared_ptr(), garbage
collectors and similar machinery. For example, if one wants to post the
*exPtr or the pointer to _EXCEPTION_POINTERS that it contains onto to a
queue from where a separate task would process all the exceptions
asynchronously, RAII will not help.
BTW, some Microsoft's apparently strange habits in using C++ become
easier to come to terms with if one keeps in mind their strong
background in "asynchronous message-driven" programming paradigm. When
this paradigm is used, the message sometimes originates in one "piece"
of the program (whether the piece it is a thread, a process or a module)
and is to be processed and destroyed in another. It is not always
possible to use RAII in such code.
Regards
-Pavel
Cheers, & hth.,
- Alf