Re: Why doesn't this code generate an inaccessible memory-error?
Nick Hounsome wrote:
On 10 Feb, 01:17, achp <achp...@gmail.com> wrote:
I agree that it would be weird (even though permissible from formal
point of view) for an implementation to throw an std::exception from
std::vector::operator[].
I think you will find that many do so when compiled with DEBUG and I
don't find it weird at all.
Which implementations? I was under the impression that leaving on the debug
checks was a VC-ism and not generally accepted behaviour.
Bad index usually results from a serious
error in program code and there is no need for any continuation or
handling of such a situation.
[...]
If the implementation detects it, it
must report failure immediately.
No. It is UB.
I think the "must" was rather a strong statement of his feelings how an
implementation should behave. According to the C++ standard, we all know
it's UB.
If it does not, the error may be caught by an unaware catch clause
and escape from the attention of programmer.
I think that you are arguing against yourself - you just said that it
was weird to throw an exception.
If the program doesn't catch the exception then the application is
terminated anyway.
A program should only catch in a limited set of circumstances:
1. The exception is "expected" and recoverable (e.g. file not found)
2. The exception is unexpected but the policy is to carry on in the
hope that this will be less bad than terminating.
In case 1 there is usually user interaction.
In case 2 there will always be an attempt notify someone of the
problem either by UI or log file so it doesn't escape the attention of
the programmer.
Example:
container<record> data;
...
try {
size_t index;
cin >> index;
record r = data[index];
std::cout << "record " << index << " = " << r << std::endl;
} catch(std::exception const& e) {
std::cerr << "Failed to read record! (" << e.what() << "'\n";
}
If an out-of-range access throws, the invalid index will trigger the correct
error handling. If you now compile the code without the range check
(release build), it will cause bad behaviour. Obviously, for the above, the
correct code would be
record r = data.at(index);
or an explicit range check to clearly show that you don't expect the index
the user entered to be in range. Further, you should check that the input
operation actually succeeded etc.
The main problem above is that people regularly wrap large blocks of code in
a try/catch clause and that they catch std::exceptions there. If the debug
helper code now starts throwing such an exception, its behaviour is
suddenly far away from the code without the debug helpers. If it throws at
all, IMHO that exception should _not_ be derived from std::exception. Since
throwing however implies that it can be caught and handled, which isn't the
case when you simply invoke UB, I would rather say that aborting is the
right way to go.
Exceptions are not about handling errors in programming, they are
about handling *legal* and *expectable* situations disruptig the
normal program flow.
100% Agreed. But remember that "normal" control flow can easily differ
between DEBUG and non-DEBUG builds even without exceptions because the
timing and memory layout differences alter the effects of bugs.
Yes. However, you usually want the debug build to behave similar to the
release build, and throwing exceptions in debug builds that could be caught
and ignored otherwise just doesn't help. I want all my programming errors
to come up as early, clearly and loudly as possible, invoking normal error
handling mechanisms are not good enough, in particular since they can
easily be muted unintentionally.
Uli
--
Sator Laser GmbH
Gesch??ftsf??hrer: Thorsten F??cking, Amtsgericht Hamburg HR B62 932
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]