Exceptions, Go to Hell!

R

RB

I agree with you. And even so the compiler switch does not actually turn
off exceptions from happening (as I am sure you are aware of ) but rather
only turns off the ability for SEH type exceptions from being caught in the
compiled code. The final CRT caller and/or OS handler will still put a crash
dialog in my face if the violation is serious enough. And if it is a lesser infraction
my app continues along like a person with colon cancer but no colonoscopy test
to tell him it needs removed. I'm sure you can guess the results of that scenario.
But admittedly the OP says that his calling code takes care of any errors.
And I don't doubt his competence which is probably much higher than mine.
What I do doubt (from within my competence level ) is how his calling code
is going to cover uncontrollable items that may happen while inside the STL lib ?
Is his error covering code going to be able to back out of STL, destruct any
allocated items and reset any items that have traversed to current expecting
completion ? Granted a good lib ( like STL ) would do that on it's own BUT
the vehicle for doing so would be exceptions.
 
G

Goran Pusic

Hi Goran, ( I am assuming you are the same Goran that used to help
                  me on ms.public.vc.mfc before ms shut down the server )
   I have studied exceptions quite a bit since you and Joe patiently
helped me. Though still much a novice dummy overall, from what
I have learned on exceptions I agree with your post.
   It would appear to me that either you would have catch and handle
or swallow with "a catch and do nothing" if you were confident that your
callers error handling code could rectify the violation effects.
 OR else have the results in your face OR in your back down the road.
   I have a question at this point (hopefully I am posting this before the
Belgium time zone sleeps) and that is "exception specifications".
I.e if I define a function as:  
  int MyFunc( int Arg1, DWORD Arg2) throw( ) {.........}
(which according to data read would in some cases denote this function
  would not throw "any" exception)
Albeit I don't see how they could be a solution for the OP since he is
dealing with a library already coded,  I still have mixed information as to how
reliable they actually are and even more so, I've read that some modern
version compilers ignore them.
  Given the inherent underlying hardware interrupt and OS implementation
it would seem that if you deny "some" exception handlers from taking place,
your machine would either blue screen crash or take off on an endless loop.
While lesser infractions would let the function or application or machine limp
along until a corruption is exposed and causes a failure of related consequence.
What is your knowledge on this.

I suggest you take a look at what Herb Sutter has to say on exception
spec (basically: they way they are defined by C++, are useless :) ).
(Search gotw.ca for "throw()" ). His explanation is much better than
anything I can come up here. :)
Further for your comment or correction a few current concepts of mine.
1. Any exceptions thought of  "not needed to be caught" would have to
    be coded (in a perfect program) so that the exception never happens.
    And debuggers can help make this more of a conceivable reality.
2. But debuggers cannot prevent a user opening the wrong file or
    wrong format, or a third party lib foo bars or any other scenario that is
   out of the control of the end product programmer.
3. It would appear that exceptions are a reality that hardware and OS
    engineers deemed necessary to promote their product as more stable.
    Even with the most foo bar programmer (in many cases like myself) the
    underlying hardware/OS partnership brings up the crash dialog that
    basically says "Your App programmer FooBarred so let him know"
    Without exceptions the user sits at his screen wondering "WTF ! my
    computer just broke".

Well, I am not so sure about that. To me, exceptions are a way to
__structure code in face of unexpected situations__. They are not
there to "handle errors", and they are certainly not there to somehow
handle __coding errors__ (that's IMO a massive error many people
make).

And indeed, if you look at your OS, it does __not__ emit any
exceptions in C++ sense (nor in any other language sense, really). Not
even Windows does that. When you receive windows exception (SE one),
your code is already dead.

Effectively, exceptions help you to eliminate a myriad of error code
paths and transport error info to a place where you can do something
about that error. No more, no less. In a way, when speaking about
exceptions, I often say "forget error __handling__, there is no such
thing". Because, what we call error handling, exceptions or not, is
almost always "clean up and get out, report error to some external
factor". It's _resource handling_ (and sometimes, program state
handling), on one hand, and _error reporting_, on the other. 'cause,
situations where error happens and code can correct it, are __rare__.
And that's the ultimate reason why exceptions are so good - they help,
massively, in handling common situation where, upon error, all you can
do is to clean up and get out.
4. Any exception that should be caught is one that the "error handling code
    was not able to control " OR the exception structure excels as a vehicle for
    covering an expanded area of code that needs to unwind, destruct, delete
    and or reset items that have traversed up until the exception occured.

This part I don't understand, sorry.

Goran.
 
F

Francesco S. Carta

<snip>

Sorry for dropping in with such a request, but you should really do
something about the formatting of your posts. Reading them is far from
comfortable.

Assuming you're doing this: please avoid breaking lines when you reach
the edge of your screen.

Assuming you're not doing this: please separate your paragraphs with two
"enter" keystrokes.

I seem to recall that you have set your (weird) newsreader (Outlook 6)
with some large line-length and that you have some sort of issue with
mixed end-of-line markers.

I strongly advice you to get a better newsreader.

Shall you need help about this feel free to ask either here or via
private email, and many people will avoid some headaches.
 
T

tni

That's quite alright, except that it's not really nice to abort on
bad_alloc in particular. That's almost always too harsh.

It's only OK if the whole program is one "do work" iteration, and even
then, it cost little to write one catch in main(), e.g.

int main()
{
try { return work(); }
catch(const exception& e) // perhaps bad_alloc, perhaps something
else.
{ return error_code_from_exception(); /*nothrow guarantee here*/ }
}

Goran.

That only works if you write exception safe code. If you don't (and I
have the distinct impression the OP doesn't want to), you want to abort.

If you have an OS that overcommits memory, you very likely won't get a
bad_alloc anyway.
 
Ö

Öö Tiib

Well, no, not really. You see, it all depends on what program does. If
program is one iteration of some work, then OOM is indeed the end of
the world.

I said OOM is end of the world for ordinary function that did
something that may cause some allocation, in my example
std::vector::push_back(). Grep for "push_back" in some C++ code base
to identify them. So it should keep its hands in pocket and not touch
std::bad_alloc. It is way ower head issue for it. I did not say that
it is likely end of world for a *program*.

If your program contains operations that may be too memory consuming
and whose failure is not end of the world for whole application then
put catch(std::bad_alloc const&) around these too. Can say to user
that "kill some other apps and try again". But i see i mentioned that
too in the piece you quoted above.
 
R

RB

"exception specifications"...................
I suggest you take a look at what Herb Sutter has to say on exception
spec (basically: they way they are defined by C++, are useless :) ).
(Search gotw.ca for "throw()" ). His explanation is much better than
anything I can come up here. :)

Thanks will do that soon.
Well, I am not so sure about that. To me, exceptions are a way to
__structure code in face of unexpected situations__. They are not
there to "handle errors", and they are certainly not there to somehow
handle __coding errors__ (that's IMO a massive error many people
make).

Well I totally agree with your above sumation, BUT what I was attempting
to say was "all " of the exception ability (even c++ ) is created (albeit expanded)
on top of the basic provided by the hardware interrupt system and OS partnership
of the linked list of handlers at FS:[0]. That said I was stating the "origin" of said
capability was (as I see it ) the promotion of a more stable computer product
(or least an informed exit ) as opposed to an unlabeled crash.
And indeed, if you look at your OS, it does __not__ emit any
exceptions in C++ sense (nor in any other language sense, really). Not
even Windows does that. When you receive windows exception (SE one),
your code is already dead.

Well no I must have been ambiguous, since I did not mean that the OS would
implement an exception frame that would comply with the trylevel and scopetables
of the C compiler's SEH or the similar but syncronous C++ with trylevels only and
no scopetable implemenation. But the OS itself can also have uncontrollable aspects
that it may it may have to emit (throw) an exception on it's own, OR handle an a
hardware violation from the hardware interrupt table, if the running process doesn't
handle it first. And as for your code being dead already, of course in most cases the
programmer cannot be aware enough of the voilation code to reset a null pointer (etc)
in the Context structure and return a continue_execution at the same violating address.
And even if it the progammer was aware it would ( I think ) be more appropriate to
rather use such an exception as an opportunity to implement a a crash report and a
polite exit. Then use such to create a code update.
This part I don't understand, sorry. Goran.

Ok, well apologize for ambiguity on my part, but in many ways I am attempting
to say the same concept as your post on an above thread repasted below,
 
J

James Kanze

[...]
When you start thinking about how you would be able to detect
any possible errors with STL containers, you will find that
exceptions are, in fact, the *easiest* and most practical way
of doing that.

Independently of easiest or most practical, exceptions are the
way the standard library expects errrors like insufficient
memory to be reported. Within the library, when the code calls
an allocator, it doesn't test whether the allocator returned
null or not; it supposes that the pointer it got back is good
(and that if the allocation failed, an exception was raised, so
that the library doesn't have to deal with it later).

One can conceive of other solutions (although as you say,
they're likely to be more complicated), but that's the solution
the library uses, and it doesn't work any other way.
 
A

Andrea Venturoli

Il 08/24/10 16:45, RB ha scritto:
What I do doubt (from within my competence level ) is how his calling code
is going to cover uncontrollable items that may happen while inside the
STL lib ?
Is his error covering code going to be able to back out of STL,
> destruct any allocated items and reset any items that have
> traversed to current expecting completion ?

That question is bad posed: stripping off exceptions doesn't make an
interface grow any other mean of communicating problems.
So you can't treat them, since you don't know they are there.

bye
av.
 
K

Kai-Uwe Bux

Daniel said:
I worked in a shop like that once. We wrote our own string, vector and
map classes that had the same interface as the STL classes (our string
class was cleaner though,) and any situation where the standard class
would have thrown an exception, our classes aborted.
[...]

The OP made me think about that. I wonder: couldn't you do that via a custom
allocator (maybe even an allocator adaptor) instead of doing it over and
over for each container?


Best

Kai-Uwe Bux
 
D

Daniel Pitts

Hi,

Sometimes I found it very convenient to use STL in my application.

But one thing I hate is that STL containers throw exceptions. Because
we handle errors explictly in our application, we don't want
exceptions.

I want to know whether there's any possibility to turn exceptions off,
just like the "new(std::nothrow)" option.

Specifically, will the following operation throw exceptions? How to
handle it without the "try, catch" clause?
Don't put in a try/catch block, and let your program abort.This snipped is undefined behavior, with or without exceptions.

The funny thing about out-of-memory exceptions, is that often the only
thing you *can* do is abort. There are some situations where you can
successfully recover, but you better not be using threads, and you
better have a comprehensive recovery strategy.
(Don't teach me the benefits of exceptions)
While I cannot teach you something you are unwilling to learn, I will
express that exceptions are necessary, not just beneficial, to
programming in C++. In other words, I won't teach you the benefits, but
know it is a necessity.
 
G

Goran Pusic

That only works if you write exception safe code. If you don't (and I
have the distinct impression the OP doesn't want to), you want to abort.

Heh, that's very true. However, aborting is a massively substandard
coding (to me at least, and especially in C++, where language
capabilities - think RAII - make any recovery a breeze). And e.g. no
library code should ever do it, 'cause it's not library writer's
choice to make.

On top of that, both exceptions and premature returns require similar
approach to coding. Premature return is effectively very simple coding
strategy, e.g. (using ScopeGuard and counting absence of any other
resource handling class):

RESULT_TYPE f(params)
{

RESOURCE_TYPE1 r1 = alloc1();
ON_BLOCK_EXIT(free, r1);

// rinse, repeat this, add more resources
RESULT_TYPE r = call1(params);
if (failed(r))
{
assert(0);
return r;
}
// By the way, you can wrap 6 lines above in a macro, so you get
e.g.
// CHECKED(RESULT_TYPE, call1(params));

RESOURCE_TYPE2 r2 = alloc2();
ON_BLOCK_EXIT(free, r2);

...
return RESULT_TYPE(SUCCESS);
// Any resources freed automaticaly by scope guards
}

(It's similarly simple if some resource(s) should be a e.g. return
value or kept for later in some global state, but then one would use a
Make(Obj)Guard and "Dismiss").

All in all, exceptions or not, in C++, code that is exception safe is
also __extremely__ simple in form, and works correctly even if you put
exceptions out of the picture.
If you have an OS that overcommits memory, you very likely won't get a
bad_alloc anyway.

Yes. BTW, I hate overcommit, because large swaths of people have
experienced it and now think that handling memory correctly is
effectively futile. But that's not how C, C++, nor many other a-
language, is meant to work, not at all.

Goran.
 
Ö

Öö Tiib

On top of that, both exceptions and premature returns require similar
approach to coding. Premature return is effectively very simple coding
strategy, e.g. (using ScopeGuard and counting absence of any other
resource handling class):

RESULT_TYPE f(params)
{

  RESOURCE_TYPE1 r1 = alloc1();
  ON_BLOCK_EXIT(free, r1);

  // rinse, repeat this, add more resources
  RESULT_TYPE r = call1(params);
  if (failed(r))
  {
    assert(0);
    return r;
  }
  // By the way, you can wrap 6 lines above in a macro, so you get
e.g.
  // CHECKED(RESULT_TYPE, call1(params));

  RESOURCE_TYPE2 r2 = alloc2();
  ON_BLOCK_EXIT(free, r2);

  ...
  return RESULT_TYPE(SUCCESS);
  // Any resources freed automaticaly by scope guards

}

I don't understand that "assert(0)" part. It reads like "abort()" for
me and "return" after it seems unreachable code.

[...]
Yes. BTW, I hate overcommit, because large swaths of people have
experienced it and now think that handling memory correctly is
effectively futile. But that's not how C, C++, nor many other a-
language, is meant to work, not at all.

That overcommit is red herring since it can be turned off with some
kernel parameter like "vm.overcommit_memory = 0". If an user refuses
to turn it off and random apps he runs get killed randomly then it is
his fault, why should you care.
 
T

thomas

Something that comes close to what I described in the paragraph you
decided to snip (without marking that you've done so) almost
completely. If C++ could generated two versions of the same function,
one using exceptions and one using error codes, this may be a useful
feature. Personally I don't have a problem with exceptions, even
though I think that try-catch-statements can make code unreadable
(which is why I use my personal pre-processor macros to hide them).

All I have to say is that there are cases where the user of some
library (in this case STL) wants to check every single operation, and
sometimes he may only be interested whether a lot of operations
succeeded. In the first case he'd prefer error codes, in the second
case exceptions. But noone wants to write two versions of the same
function, so it would be nice if C++ could generate two versions of a
function from a single definition (like the #import'ed type libraries
under Visual Studio).

Regards,
Stuart

I agree.
 
G

Goran Pusic

Frankly, I agree with Öö Tiib. It has been my experience that if my
program threw an exception, any exception, I had to re-write it so that
it no longer threw the exception.

Even if exceptions was due to network failure that prevented a file
from being open? No, that's too harsh. That said, I agree that there
are situations where you'd say "well, this ate resources and it needs
to be rewritten".
If the code's result is required for proper program functioning, and it
fails (throws an exception,) then the code has to be re-written so that
it won't fail anymore. If the code's result isn't required, then why
call the code in the first place?

(I'll restrict my discussion to OOM conditions).

Approach you're advocating works only where you can, through external
means, guarantee that you'll have enough memory for whatever you want
to do. I'd say that reduces your set of runtime environments.

But in general, that's a tough call. Who's to prevent users from
running the code on a system with less memory? Who's to prevent the
administrator to reduce working set of the process? Who's to prevent
the user to use virtual memory up to the full? Etc. What I spoke about
(clean-up, get out, continue with something else) applies in all these
cases.

In general, there's too many factors out of your control. In my view
if bad things __can__ happen, they __will__ (I am old :) ). So your
"there will be memory" approach does not fly all that well for me.

Goran.
 
G

Goran Pusic

Personally I don't have a problem with exceptions, even
though I think that try-catch-statements can make code unreadable
(which is why I use my personal pre-processor macros to hide them).

Are you using RAII well? ScopeGuard?

If not, start using it.

If yes, you should have tiny mini micro number of try-catch-es in
code. If you don't, there's something wrong with the way you do
things. ( Yes, I am prick enough to say that without even knowing what
your code looks like ;-) ).

Goran.
 
K

Kai-Uwe Bux

Goran said:
Are you using RAII well? ScopeGuard?

If not, start using it.

If yes, you should have tiny mini micro number of try-catch-es in
code. If you don't, there's something wrong with the way you do
things. ( Yes, I am prick enough to say that without even knowing what
your code looks like ;-) ).

I am curious: if I use a function that communicates failure (or some other
condition) via throwing, how can RAII or ScopeGuard help me to avoid a catch
statement?


Best

Kai-Uwe Bux
 
J

James Kanze

On 25 aug, 10:35, Goran Pusic <[email protected]> wrote:

[...]
I don't understand that "assert(0)" part. It reads like
"abort()" for me and "return" after it seems unreachable code.

Typically, with assert(0) you'll get an error message with the
line number and filename where the assert occurred. And the
return after it isn't unreachable if the code is compiled with
NDEBUG defined. (Not generally a good idea, but sometimes you
can't avoid it.)
[...]
Yes. BTW, I hate overcommit, because large swaths of people have
experienced it and now think that handling memory correctly is
effectively futile. But that's not how C, C++, nor many other a-
language, is meant to work, not at all.
That overcommit is red herring since it can be turned off with some
kernel parameter like "vm.overcommit_memory = 0". If an user refuses
to turn it off and random apps he runs get killed randomly then it is
his fault, why should you care.

Whether it can be turned off, and how, depends on the OS---Linux
isn't the only one which overcommits. And a lot of Linux boxes
are running in situations where there isn't really a qualified
sysadmin, who can be presumed to know about such things. What
is the value set to by default on the distribution DVDs?
 
Ö

Öö Tiib

On 25 aug, 10:35, Goran Pusic <[email protected]> wrote:

    [...]
I don't understand that "assert(0)" part. It reads like
"abort()" for me and "return" after it seems unreachable code.

Typically, with assert(0) you'll get an error message with the
line number and filename where the assert occurred.  And the
return after it isn't unreachable if the code is compiled with
NDEBUG defined.  (Not generally a good idea, but sometimes you
can't avoid it.)

Yes, then it makes sense.
[...]
If you have an OS that overcommits memory, you very likely
won't get a bad_alloc anyway.
Yes. BTW, I hate overcommit, because large swaths of people have
experienced it and now think that handling memory correctly is
effectively futile. But that's not how C, C++, nor many other a-
language, is meant to work, not at all.
That overcommit is red herring since it can be turned off with some
kernel parameter like "vm.overcommit_memory = 0". If an user refuses
to turn it off and random apps he runs get killed randomly then it is
his fault, why should you care.

Whether it can be turned off, and how, depends on the OS---Linux
isn't the only one which overcommits.  

Yes, but do you know one where it is on and can not be turned off?
Linux is most widely accessible OS that has overcommit so i gave it as
example. Imagining OS that has overcommit unavoidable i have to
overtake memoy management/allocation, take large chunk and fill with
random numbers to be sure it is mine. Using problematic platforms has
a cost.
And a lot of Linux boxes
are running in situations where there isn't really a qualified
sysadmin, who can be presumed to know about such things.  What
is the value set to by default on the distribution DVDs?

The ones i have some experience with had it set 0 by default. I have
quite limited experience with Linux so i do not know, but having it on
by default sounds like having some "run unreliably" setting turned on
by default.
 
G

Goran Pusic

I am curious: if I use a function that communicates failure (or some other
condition) via throwing, how can RAII or ScopeGuard help me to avoid a catch
statement?

Well... I __guessed__ that OP who complained about try/catch had too
many of them (perhaps I was wrong), and that they were caused by the
following situations:

{
TYPE r = alloc(); // r holds a resource; we must free it at the
block end.
workworkwork(); might throw, or simply return prematurely
free(r);
}

so you'd do:

{
TYPE r = alloc();
try
{
workworkwork();
free(r);
}
catch(...)
{
free(r); // must be a no-throw operation.
throw;
}
}

This alone is ugly, now imagine that you have another (or more)
resources in that block.

So, if you use RAII (that is, have resource-wrapper class for TYPE),
or scope guard, try/catch-es like above all disappear (as well as
multiple calls to free).

The number of "other types" of try/catch statements in code is IMO
very, very small. And the bigger the code base, the smaller it is
(compared to said size).

Goran.
 
V

Vladimir Jovic

Goran said:
Even if exceptions was due to network failure that prevented a file
from being open? No, that's too harsh. That said, I agree that there
are situations where you'd say "well, this ate resources and it needs
to be rewritten".

You can terminate the application, pop the information box and wait, or
do something else. But you will not continue the execution like nothing
happened. What else can you do if required conditions are not met?
(I'll restrict my discussion to OOM conditions).

Approach you're advocating works only where you can, through external
means, guarantee that you'll have enough memory for whatever you want
to do. I'd say that reduces your set of runtime environments.

But in general, that's a tough call. Who's to prevent users from
running the code on a system with less memory? Who's to prevent the
administrator to reduce working set of the process? Who's to prevent
the user to use virtual memory up to the full? Etc. What I spoke about
(clean-up, get out, continue with something else) applies in all these
cases.

In general, there's too many factors out of your control. In my view
if bad things __can__ happen, they __will__ (I am old :) ). So your
"there will be memory" approach does not fly all that well for me.

Can't beat Murphy's law.

If the program is for an embedded system (where everything is set), then
running out of memory can be solved only in two ways :
1) add more memory
2) see if you can reduce memory usage, but that is usually hard

btw every commercial software has minimal and recommended requirements.
If you fail to satisfy them - too bad, it will not run.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,120
Latest member
ShelaWalli
Top