Re: Exception handling Organization: unknown
On Sep 30, 10:45 pm, Zeljko Vrba <mordor.nos...@fly.srk.fer.hr> wrote:
On 2009-09-30, Goran <goran.pu...@gmail.com> wrote:
Apropos that, where/how is that object allocated?
I have to ask: do you think that matters? I can easily say: no, it
does not. But let's explore that, fire away.
And most importantly, WHEN is it allocated? It matters if the implementation
of exceptions has to be robust -- what happens if there is not enough memory
to allocate the exception object? You can't throw bad_alloc, because that's
an object as well.
As I said, that does not matter. Exception object is (normally) not
allocated on the heap, but on the stack. Also, bad_alloc in
particular, is kinda like a POD, it's void of exceptions. That is an
essential "implementation quality" requirement for OOM exception, be
it bad_alloc or something else (I also know about what some people did
for OOM when they used exception objects allocated on the __heap__).
I kinda knew that this was going to be the question, and I know all
the answers in vicinity. ;-)
(If by "out of memory" you also mean "out of stack", I think that you
are mistaken; stack is always considered as available. AFAIK there's
nothing available in the standard to treat stack exhaustion in any
way. Doing that is +/- difficult in practice and platform dependent.
So IMO, stack exhaustion == crash.)
Compare to error-return:
if(!(f = fopen(...))) crap!
if (!read(f...)) crap!
if (!read(f...))crap!
It will most likely be if(read(...) != expected_amount) // crap!
And note that it is valid (and often practical) to specify a larger
buffer size to read than the size of data you expect.
In your opinion, should a partial read throw an exception or not?
Because of EOF, no. If code knows where the file ends, then yes. I see
what you did there, good one! ;-)
Exceptions are so intrusive mechanism that no code should use it for reporting
anything but "something has become FUBAR." File not found, failing to parse an
integer, key not found in a dictionary are not FUBARs. Accessing a
non-existant element in a vector is (undefined behavior), as would be e.g.,
deleting an already deleted object (a situation sadly often not detected), or
corrupting a state of some object through a rogue pointer (and the object's
methods detect it).
Whoa, whoa... No, no, no, the last three are a cold crash. Exceptions
do not matter __in the slightest__. Just stop that.
No, the last three are valid examples of what can go wrong. vector::at throws
an exception for an out-of-range index. An object's state can be corrputed
(i.e., the object's invariants broken) by bugs other than invalid memory
accesses. Double delete is indeed a "cold crash", but why should it be? By
sacrifising some performance, a smart memory allocator could detect it.
There's a clear distinction of two types of wrong: error in code
execution and a bug. I am not discussing the latter any further.
By "vector", I thought of a raw C array, my bad. I do agree WRT broken
invariants (does not __have__ to be a crash).
To me, OOM is a clear-cut use case for exceptions. Having to check
every single allocation? No thanks, I've got better things to do in
life!
Which returns us to the first question: how/where/when is the bad_alloc
object allocated?
OK, I propose this: provoke OOM in correct code and you'll see that
all goes well (I did it numerous times, it does). If you get a
problem, you either have a bug in your code, or a bad implementation.
(I do hope that we agree that OOM killer on systems with overcommit is
outside of the scope of discussion; if you are indeed running on e.g.
Linux, I suggest you try to provoke OOM by fragmenting, not
exhausting, memory; that can fool OOM killer better).
By the way, do you wrap all your non-trivial destructors in a try { }
catch(...) { } clause?
Ah... That's rule 0 of exceptions you're ignoring here: destructors
must not throw. That's not specific to C++, and there's more general
rule behind that. The rule is: cleanup operations always "succeed" (or
else, code is a mess). We can discuss that, too.
I asked that question exactly because I know about that rule. Can you *prove*
by static inspection of your code (i.e., without testing it) that none of your
destructors throws?
No. __I__ have to write them like that. But, do you think that's hard?
IMO, it is not. On (very) rare occasion where failed cleanup operation
must be handled, an out-of bad technique must be used (BTW, if you
think about that, it's the case anyhow, exceptions or not). Failed
cleanup should most often^ be either treated as a crash or ignored.
E.g. you close any "local"^^ system handle, and that fails: either
there's already a bug in code (so crashing right there could help),
either there's really bad problems in the system itself (who wants to
be running on trashed system?). In all honesty, in my professional
career, I have never seen failed cleanup that was not caused by a bug
in code.
^like, 99% of cases
^^e.g. not file on network
Fair enough, however... I said (but now, with precision) "__First__,
use stat or PathFileExists" ;-). In a way, what you propose is a silly
design: you want to know if a file exists; to do that, you __open__
it. WTF, isn't there a better way!?
Not within the boundaries of standard C and C++, as far as I know.
True. However... Nyah, nyah, nitpicker! ;-)
And on some platforms, there might not be a better way.
So... You have a platform that has CRT, but not POSIX (for stat)? Wow,
I'm impressed ;-).
Goran.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]