Prev: Exception Semantics question
Next: Getting value of a input attribute ‘id’ of a resource in a webpage
From: Giovanni Dicanio on 25 Jun 2010 07:02 On 25/06/2010 12:16, Goran wrote: > It's true, ultimately, one can use ATL without exceptions. I would > never do that, nor recomment that idea to a good friend ;-). :) However note that this is part of Google C++ Style Guide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Exceptions_to_the_Rules <quote> Although you should not use exceptions in your own code, they are used extensively in the ATL and some STLs, including the one that comes with Visual C++. When using the ATL, you should define _ATL_NO_EXCEPTIONS to disable exceptions. You should investigate whether you can also disable exceptions in your STL, but if not, it is OK to turn on exceptions in the compiler. (Note that this is only to get the STL to compile. You should still not write exception handling code yourself.) </quote> I think they used that rules also in building Chrome browser...and I like it, and it seems to work "exceptionally" :) fine. > By the way, for that reason, I have (had?) a pure ATL (no MFC) project > where I rig set_new_handler to throw CAtlException(E_OUTOFMEMORY). > That gives me "normal" ATL context, and STL containers are throwing > that instead of bad_alloc. Of course, doing that also means that > __any__ other (standard C++) exception going out of STL containers is > a bug, but that is, in fact easy - if they happen, there indeed is a > bug in code. So for that project, my base exception class is > CAtlException. bad_alloc became CAtlException(E_OUTOFMEMORY). I also > had a derivative that had more info in it, e.g. error text for ATL's > Error function. So all COM-boundary methods (virtually all, there's a > couple trivial prop getters) are in fact: > > HRESULT Method(params) > { > try > { > workworkwork(); > return S_OK; > } > catch (const CAtlException& e) > { // Nothrow zone here. > return MyOwnErrorThatCallsATLsError(e); > } > } I think it's a good pattern. > It's not me who came up with this idea, I stole it from C++ Builder > (Borland tech people knew their programming, Yes, and note that one of the Borland heros is here: David Ching! :) > pity about the rest of > the company). There, any new COM-boundary method in ATL projects is > generated like that by the IDE. This could be a proposed enhancement to VS IDE. Or alternatively you could #define macros e.g. #define ATL_EXCEPTION_GUARD_BEGIN try { #define ATL_EXCEPTION_GUARD_END return S_OK; \ } \ catch (const CAtlException & e) { \ ... some non-throwing code \ ... some non-throwing code return e; \ // implicit HRESULT cast } and usem them like this: HRESULT Method(params...) { ATL_EXCEPTION_GUARD_BEGIN DoSomeWork... ATL_EXCEPTION_GUARD_END } Giovanni
From: Giovanni Dicanio on 25 Jun 2010 10:36 On 25/06/2010 14:00, Goran wrote: > The thing is, simply: there is NO standard C++ without exceptions; STL > throws, heck, even string+string throws, and one can't reasonably > escape that. The point to me is that string+string wisely throws, because it is an *exceptionally bad* situation! If there is no more memory in the system to concatenate two strings, then the wise thing to do is tidy up (thanks destructors and stack unwinding) and quit. The problem - to me - is the *abuse* of exceptions. Giovanni
From: Joseph M. Newcomer on 25 Jun 2010 16:56 Generally, exceptions are good ways to get back to a clean point where things might be recoverable. For example, I believe there is exactly ONE correct way to terminate a thread: return from the top-level thread function. Period. Nothing else is viable. Mostly this deals with making sure all the destructors on the stack are executed (::ExitThread and its various disguises are Unacceptable). So my top-level thread functions often look like try { var->RunThread(); } catch(CTerminateThreadException * e) { e->Delete(); } return 0; and I will throw new CTerminateThread(); when I get into such deep trouble that the thread must die. Before that, I have logged the event, made preparations to alert the user (usually by a PostMessage to the main GUI thread), and done whatever I can to maintain the integrity of the operation (usually by ensuring the postconditions are not violated) I also believe that you should never, ever, under any circumstances, call exit(int) in the main GUI thread (and this includes all of the various guises). The main GUI thread can ONLY be terminated by the user choosing File>Exit, period, unless you build in a recover-and-restart capability. However, when I throw a CTerminateApp exception (after something ugly like running out of memory or being so unrecoverably screwed up that he user cannot proceed) I disable all menu items which require a correctly-working program (so Help>About, Help>Index, File>Exit, etc. still work, and depending on the context, perhaps File>Save, and File>Save As, so the user can save current state), but all other work that, for example, might require memory iallocation will be disabled. In one case, I had to change the menu to be File>Save Recovery File, because File>Save[As] required allocating memory (we were being done in by some horror of a service that expanded to fill the entire paging space!) There is nothing more upsetting to a user than to do something, anything, and have the app disappear suddenly without a trace. And this is a tech support nightmare. Anyone dumb enough to put exit() calls in a GUI app probably has dozens of them, so when it happens there is NO WAY to guess which one did it (I've had to field tech support calls for software that did this, and it took me days to remove all the exit() calls!) There was once a database library for dBase IV files that had several nasty properties (a) when an error occurs, pop up a ::MessageBox(NULL, ...) (b) whether (a) is done or not, exit the app if there is an error (c) do not document the preconditions for each library call, but when things go wrong, follow (a) or (b) above (d) never, ever under any circumstances return an error code to the application program; instead, do (b), perhaps preceded by (a) The result was that you could get a MessageBox that appeared UNDER the app (because it was owned by the desktop). The code for handling this was so convoluted (in the interest of "being fast") that nothing short of a total rewrite of the error handler could fix it. There was a library call to set the MessageBox window, but the variable it set was systematically ignored by every ::MessageBox call. I believe the rise of Access ahd the demise of dBase eventually put this company out of business, although their own programming incompetence was well on its way to doing so. Note that the ::MessageBox text did not even make sense ot a *developer*, let alone an end user. The assumption that a library is permitted to exit a program is fatal, and should be the basis of firing-for-cause. joe On Fri, 25 Jun 2010 16:36:53 +0200, Giovanni Dicanio <giovanniDOTdicanio(a)REMOVEMEgmail.com> wrote: >On 25/06/2010 14:00, Goran wrote: > >> The thing is, simply: there is NO standard C++ without exceptions; STL >> throws, heck, even string+string throws, and one can't reasonably >> escape that. > >The point to me is that string+string wisely throws, because it is an >*exceptionally bad* situation! If there is no more memory in the system >to concatenate two strings, then the wise thing to do is tidy up (thanks >destructors and stack unwinding) and quit. > >The problem - to me - is the *abuse* of exceptions. > >Giovanni Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Goran on 28 Jun 2010 04:57 On Jun 25, 4:36 pm, Giovanni Dicanio <giovanniDOTdica...(a)REMOVEMEgmail.com> wrote: > On 25/06/2010 14:00, Goran wrote: > > > The thing is, simply: there is NO standard C++ without exceptions; STL > > throws, heck, even string+string throws, and one can't reasonably > > escape that. > > The point to me is that string+string wisely throws, because it is an > *exceptionally bad* situation! Well... Any operator overload should throw, because at any rate that's how operator overloads should signal errors in C++ (anything else is ugly). So yes, it's wise. On the other side, I disagree that string + string is necessarily an "exceptionally bad" situation. One could come up with a myriad of reasons why e.g. there isn't enough memory to add these two. If nothing else, strings are often user input on one or other shape or form. Who knows what user typed/copypasted in, or whatever might have been the source. So the resulting text is too long, so what? That's not "exceptionally bad", that's just "whoops, OOM, can't do that". In other words, you can't always say that what might be bad (or even simply over-optimistic) manipulation by the user, is "exceptionally bad situation" ( and with an exclamation mark, no less ;-) ). In fact, I'd argue that most OOM conditions in correct code often happen like this: for whatever reason, program suddenly needs to allocate a __big__ chunk, and there's no space, either at the time (system already charged), either at all (won't fit in memory anyhow). And at the same time, there's plenty of space for other operations that code might want to do. Goran.
First
|
Prev
|
Pages: 1 2 Prev: Exception Semantics question Next: Getting value of a input attribute ‘id’ of a resource in a webpage |