Re: Exception Handling
On Sep 16, 1:43 pm, dushkin <talt...@gmail.com> wrote:
Hi All,
I am having a problem understanding the MFC EH(Exception Handling)
classes issue.
I think I have a fair understanding about the mechanism of the EH. So
I create my own Exception classes, throw them and then catch them.
But what about the MFC Exception Handling classes? When and how can I
use them?
In code made to run withing the context of MFC, it's best if you
derive your own exception classes from appropriate MFC exception
classes. This is because MFC code itself expects and handles MFC
exceptions only. Most notably, if you ar running run-off-the-mill UI
code, with standard MFC event loop (a dialog app, windowed appp, doc/
view app...), MFC catches and handles any exceptions that derive from
CException. You can also override/improve that behavior (refer to
CWinThread::ProcessWndProcException).
Should I check every time on MSDN if the function throws
some kind of exception?
MFC is made so that when function returns e.g. a BOOL, it _generally_
does not throw. Such MFC functions are thin wrapper around
corresponding Windows calls, and OS has C interface and does not throw
C++ exceptions. You should perhaps know that Windows does throw what
Microsoft calls "structured exceptions", and these are __not__ C++
exceptions, and experience shows that you should not try to catch
these; if they happen, you have a bug that you need to correct, not
sweep under the carpet.
That said, MFC function can throw^^^. Even most simple ones like
CFile::Open. CFile::open can throw because it allocates a CString
object to remember file name. If there's no memory when you call Open,
said assignment will throw CMemoryException (slim chance, but you have
been warned). Conclusion: you must write your code to be exception
safe. Learn about exception safety (e.g. start here:
http://en.wikipedia.org/wiki/Exception_handling#Exception_safety). C++
is a very good language when it comes to writing exception safe code,
due to widespread use of RAII idiom. Learn RAII, and learn ScopeGuard
(http://www.drdobbs.com/184403758).
^^^More general rule: ___everything throws___, except code
specifically crafted not to throw (examples: primitive type
assignments (int, pointer etc), any swap() function, cleanup
functions). Everything else throws. That's how you should approach
coding in C++. You should never __think__ about whether some call
throws. That will not get you far.
You should also make sure that your own code, most notably overrides
of MFC functions, does not throw any exceptions. E.g. if you write a
handler for WM_CREATE (OnCreate), you should wrap it into one giant
try/catch and return -1 from catch, like so:
int CMyWnd::OnCreate(whatever)
{
if (__super::OnCreate(whatever))
return -1;
try
{
WorkWorkWork();
return 0;
}
catch(CException* p)
{ // No-throw zone here; you must make sure that no code here
throws.
ReportErrorOrCopyErrorInfoForLater(p);
p->Delete();
return -1;
}
}
You should only omit try/catch if you are sure that WorkWorkWork can't
throw, and that it won't throw in the future. That's a tall order, so
you should better get into a habit of writing these try/catches ;-).
Can I (how) use them to my own functions? For
example - If new() fails - should I throw a CMemoryException object?
No, absolutely not. If new fails, CMemoryException will be thrown for
you. This is because MFC overrides operator new to do it. MFC code
will never throw e.g. bad_alloc, which is what C++ standard says
operator new should do (to defense of MFC, e.g. VCL of Borland will
throw EOutOfMemory exception, and Qt says that it does not use
exceptions, but AFAIK it does, it happily throws bad_alloc, becasue
that's what standard C++ library's operator new does).
Goran.
P.S. Final word of advice: try to live by the following rule: "I am
not allowed to write any other catch except for situations like the
one with OnCreate". Instead