From: Giovanni Dicanio on
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
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
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
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.