From: Goran on
On Jan 7, 11:20 am, Peter Schneider <peter.m.schnei...(a)gmx.de> wrote:
> But I am afraid Goran already answered it here:
>
> > I don't know of any, not without massively changing your code to
> > actually crash when stepping out of bounds (that is, replacing all
> > calls to GetAt and operator[] with your own function).

I thought of one small step forward: override ProcessWndProcException
and crash on InvalidArg there. That's far away from the cause, I know,
but if you have (or add) some logging to your code, you could get
closer to it.

Goran.
From: Goran on
On Jan 7, 10:16 am, "Giovanni Dicanio"
<giovanniDOTdica...(a)REMOVEMEgmail.com> wrote:
> Some interesting readings:
>
> Cleaner, more elegant, and wronghttp://blogs.msdn.com/oldnewthing/archive/2004/04/22/118161.aspx
>
> Cleaner, more elegant, and harder to recognizehttp://blogs.msdn.com/oldnewthing/archive/2005/01/14/352949.aspx
>
> C++: do you (really) write exception safe code?http://stackoverflow.com/questions/1853243/c-do-you-really-write-exce...

Raymond is great, but IMO he dropped the big time ball in these
articles. Given that he isn't pressing on exceptions anymore, I'd
wager he saw the error of his ways. In short, his error is failure to
realize that exceptions absolutely utterly demand that one accepts
their omnipresence. Then follow

Rule 0 of exceptions: everything throws except code specifically
designed not to.

and

Rule 0.1 of exceptions: cleanup code must not throw (also known in C++
land as "destructors must not throw", in Java/C# as "code in finally
blocks must not throw", and in C land as "you don't exit prematurely
from a cleanup path").

Once that's hard set in one's mind, things get __a lot__ clearer. But
he ignores both of these rules.

So for example, AddNewGuy example should be written like this (I am
pretending that one can do ScopeGuard in C#):

Guy AddNewGuy(string name)
{
1 Guy guy = new Guy(name);
2 guy.Team = ChooseRandomTeam();
3 guy.Team.Add(guy);
4 ScopeGuard teamMembersGuard = MakeObjGuard(t, &Team::Remove, guy);
5 AddToLeague(guy);
6 teamMembersGuard.dismiss();
7 return guy;
}

And reasons why are actually quite simple once I have rules in mind.

In 2/3, I presume that an incomplete Guy instance can have a Team.
That's because Team::Remove is a cleanup operation and must not err,
per rule 0.1; so even if e.g. ~Guy() tries to call Team.Remove, all is
fine. In 4, I create a scope guard. That's because per rule 0, stuff
after 3 can throw; also, per rule 0, stuff in 4 must not throw (it's
specially crafted not to). In 6, all is fine and my guard is
dismissed. BTW, guard guards both resources and program state: if
something fails in AddToLeague, Team most likely has bad reference to
Guy, and that reference is most likely leaked (look, everyone: it's a
memory leak, in C# no less).

In Chen's other article, WRT CreateNotifyIcon function, I have to say:
1. error is easily visible (must set Icon before setting Visible), and
code should actually never work
2. actually has nothing to do with exceptions but rather with class
invariants (program logic)
3. would have been exactly the same if exceptions weren't used.

And finally, if you look at SO discussion, first answer explains quite
well what's to be done. I wish I wrote that ;-).

But it's true that even today masses of people don't know these
utterly basic things. And it's also true that good writing is not
easy. But Raymond's point ("My point is that exceptions are too hard
and I'm not smart enough to handle them.") is a cheap shot and amounts
to "I don't want to drive a car because it's easier to walk, so I'll
walk 20km to work every day".

Goran.
From: Goran on
On Jan 7, 11:20 am, Peter Schneider <peter.m.schnei...(a)gmx.de> wrote:

> I am aware that the CExceptions are handled by a try/ catch in MFC
> window proc if the application code does not handle them. But in my
> opinion and seemingly also in Goran's, this handler is doing more harm
> than good.

Ah, I missed that part initially.

No, not really, I think that this big MFC try/catch is quite alright
in general: it allows your or MFC code to throw when in trouble, and
all is well with the program; catch will call pe->ReportError() and
even inform the user (he/she might get useless error info, though). On
top of that, programmer can override ProcessWndProcException and do
whatever she sees fit with the error. So far so good.

In particular, though, I do think that CInvalidArgException is bad,
because it's usually a sign of a bug in the program. But exceptions
are strictly __NOT__ a mean to treat bugs, not in the slightest. On
top of that, there's this unlucky change in behavior between MFC
versions (bad index would essentially crash before, but will throw
now).

So I both agree and disagree with you. (I often do the same with
myself ;-) ).

Goran.
From: Peter Schneider on
On 7 Jan., 11:28, Goran <goran.pu...(a)gmail.com> wrote:

> I thought of one small step forward: override ProcessWndProcException
> and crash on InvalidArg there. That's far away from the cause, I know,
> but if you have (or add) some logging to your code, you could get
> closer to it.

Thanks for this suggestion! It's probably the best I can get.
Now if only it were possible to re-throw the original exception in C+
+ ;-)



From: Peter Schneider on
On 7 Jan., 15:32, Goran <goran.pu...(a)gmail.com> wrote:

> In particular, though, I do think that CInvalidArgException is bad,
> because it's usually a sign of a bug in the program. But exceptions
> are strictly __NOT__ a mean to treat bugs, not in the slightest. On
> top of that, there's this unlucky change in behavior between MFC
> versions (bad index would essentially crash before, but will throw
> now).

If I remember correctly, Java uses exceptions for both "normal" error
handling and for reporting programming errors including assertions.
And that seemed to work pretty well and has the advantage that there
is only one mechanism used.

Contrast this to C++ and in particular to C++ on WIN32 where there are
many different handlers for all kinds of unexpected errors (e.g.
_set_abort_behavior, _set_purecall_handler,
set_terminate,set_unexpected, SetUnhandledExceptionFilter, ...)

So where do you see the general problem with using exceptions to
report programming errors?
And how do you think programming errors should be reported in C++?

Peter