Question on vector at()

  • Thread starter Alexander Dong Back Kim
  • Start date
A

Alexander Dong Back Kim

Dear all,

I want to create a method that return an element in a vector by
selecting the element position by vector's at().

The method should be look like

vector<Apple> _appleBox;

Apple & AppleBox::GetApple (int index);

but my question is when _appleBox.at(index) is called inside of the
method GetApple, if it is out of range, an exception will be occured
so the exception handling might be

try
{
return _appleBox.at(index);
}
catch (out_of_range e)
{
return ???;
}

What should be returned when process fall into the catch statement? I
tried NULL but seems it doesn't work at all.

Any idea or advice?

cheers,
 
Y

YYweii

Dear all,

I want to create a method that return an element in a vector by
selecting the element position by vector's at().

The method should be look like

vector<Apple> _appleBox;

Apple & AppleBox::GetApple (int index);

but my question is when _appleBox.at(index) is called inside of the
method GetApple, if it is out of range, an exception will be occured
so the exception handling might be

try
{
return _appleBox.at(index);}

catch (out_of_range e)
{
return ???;

}

What should be returned when process fall into the catch statement? I
tried NULL but seems it doesn't work at all.

Any idea or advice?

cheers,

return Apple * instead of Apple & in function AppleBox::GetApple
 
R

red floyd

Alexander said:
Dear all,

I want to create a method that return an element in a vector by
selecting the element position by vector's at().

The method should be look like

vector<Apple> _appleBox;

Apple & AppleBox::GetApple (int index);

but my question is when _appleBox.at(index) is called inside of the
method GetApple, if it is out of range, an exception will be occured
so the exception handling might be

try
{
return _appleBox.at(index);
}
catch (out_of_range e)
{
return ???;
}

What should be returned when process fall into the catch statement? I
tried NULL but seems it doesn't work at all.

Any idea or advice?

Don't catch it in GetApple. Odds are that you won't know what to do
with it anyways. Let it propagate up to the caller, who will probably
have a better idea of what it wants to do with the exception.

That's the beauty of exceptions. They let the exceptional condition be
handled at the "right" level. In this case, GetApple is too low-level
to know what to do properly.
 
T

thomas

Dear all,

I want to create a method that return an element in a vector by
selecting the element position by vector's at().

The method should be look like

vector<Apple> _appleBox;

Apple & AppleBox::GetApple (int index);

but my question is when _appleBox.at(index) is called inside of the
method GetApple, if it is out of range, an exception will be occured
so the exception handling might be

try
{
  return _appleBox.at(index);}

catch (out_of_range e)
{
  return ???;

}

What should be returned when process fall into the catch statement? I
tried NULL but seems it doesn't work at all.

Any idea or advice?

cheers,

Why not check if "index" is out of range before accessing it?
Even if you try to do it in this way, I think "null" can be returned.
But the caller must make sure that it's not null before calling its
member functions.
 
R

red floyd

thomas said:
Why not check if "index" is out of range before accessing it?
Even if you try to do it in this way, I think "null" can be returned.
But the caller must make sure that it's not null before calling its
member functions.

No, NULL can't be returned -- he's returning a reference, not a pointer.
Repeat after me -- A REFERENCE IS NOT A POINTER
 
J

Juha Nieminen

Alexander said:
try
{
return _appleBox.at(index);
}
catch (out_of_range e)
{
return ???;
}

Perhaps a different design could be better here?

Usually indexing out of boundaries means one of two things:

1) It's an error, ie. a bug in the code. In this case an assert() is
usually better than throwing (because you can get the whole call stack
easily with a debugger).

2) In a few designs it's not an error at all, but intended behavior. In
these cases usually indexing out of boundaries simply returns some
default value of the element type. In that case checking the boundaries
before indexing (and returning the default value if it's out of
boundaries) is better than using at(), which throws an exception.

A third possibility where and index may be in danger of being out of
boundaries is with invalid user input. However, throwing an exception in
this case would usually be very wrong. The correct way is to validate
the user input before even trying to index anything.

I can't think of many applications where at() throwing an exception
would be in any way a desirable thing. (As mentioned, to catch
programming errors IMO using assert() is better.)
 
J

Jeff Schwab

Juha said:
Perhaps a different design could be better here?

Usually indexing out of boundaries means one of two things:

1) It's an error, ie. a bug in the code. In this case an assert() is
usually better than throwing (because you can get the whole call stack
easily with a debugger).

2) In a few designs it's not an error at all, but intended behavior. In
these cases usually indexing out of boundaries simply returns some
default value of the element type. In that case checking the boundaries
before indexing (and returning the default value if it's out of
boundaries) is better than using at(), which throws an exception.
Agreed.

A third possibility where and index may be in danger of being out of
boundaries is with invalid user input. However, throwing an exception in
this case would usually be very wrong. The correct way is to validate
the user input before even trying to index anything.

Also generally true.
I can't think of many applications where at() throwing an exception
would be in any way a desirable thing. (As mentioned, to catch
programming errors IMO using assert() is better.)

Huh? The exception is *exactly* the right solution, for the reasons red
floyd already explained.
 
J

Juha Nieminen

Jeff said:
Huh? The exception is *exactly* the right solution, for the reasons red
floyd already explained.

Could you please explain to me why is that?

If indexing out of boundaries at some place is an indication of a
programming error, ie. a bug, the best course of action is to report
immediately about this detected error, at the place where it happens.
assert() is exactly the tool designed for this: It terminates the
program immediately, and with the aid of a debugger you can see the
whole stack trace and the values of the variables exactly when the error
happened. This way the programming error can be fixed, and the indexing
out of boundaries will not happen anymore.

I can't even begin to imagine why throwing an exception instead, and
catching it somewhere else than right where the error happens, would be
a better idea.

The only advantage of throwing an exception is that the program could,
if so designed (which is often *very* laborious), continue without
interruption. However, what would the program do in that case? A bug has
been detected, and now the program knows that function is flawed, the
data is incorrect, and nothing that function returned can be relied on.
That buggy function is completely useless. What exactly is the right
course of action in this case? (And how does it differ from a simple
assert?)
 
R

red floyd

Juha said:
Could you please explain to me why is that?

If indexing out of boundaries at some place is an indication of a
programming error, ie. a bug, the best course of action is to report
immediately about this detected error, at the place where it happens.
assert() is exactly the tool designed for this: It terminates the
program immediately, and with the aid of a debugger you can see the
whole stack trace and the values of the variables exactly when the error
happened. This way the programming error can be fixed, and the indexing
out of boundaries will not happen anymore.

I can't even begin to imagine why throwing an exception instead, and
catching it somewhere else than right where the error happens, would be
a better idea.
Because the correct place to catch the error is not in at(), or in
GetApple(), but rather in the caller of GetApple(), who will have some
sense of what to do with it.
 
K

Kai-Uwe Bux

red said:
Because the correct place to catch the error is not in at(), or in
GetApple(), but rather in the caller of GetApple(), who will have some
sense of what to do with it.

That very much depends. There are two cases:

a) an out of bounds error indicates a bug in the program (i.e., something
happened that the programmer did not expect). Then code in GetApple() is in
no way better equipped to deal with the event. An assert() is the
appropriate response.

b) an out of bounds error does not indicate a bug (i.e., out of bound
indices are permitted by design). In this case, an exception is appropriate
if the condition might require stack unwinding for best handling.



I have never seen a design where an out of bounds error of type (b) was a
good idea.



Best

Kai-Uwe Bux
 
J

Jeff Schwab

Juha said:
Could you please explain to me why is that?

I think red floyd already explained it as well as I could.
If indexing out of boundaries at some place is an indication of a
programming error, ie. a bug, the best course of action is to report
immediately about this detected error, at the place where it happens.

That may be the best place to for the error to be detected, but it's not
necessarily the right place for it to be handled. In particular, part
of the code you snipped showed that the index was originally passed to
the OP's function from some client. The error is almost certainly in
the client code, not the OP's class, so it is the client who needs to be
notified. Maybe the client would like to log the error but keep the
program running, or maybe the client would like to terminate the program
altogether. This is the not for the OP's class to decide.
assert() is exactly the tool designed for this:

Nope. Assert is for documenting that a particular condition is
impossible. Assert is frequently abused to verify prerequisites, but an
assertion failure really is, by definition, an internal error.
It terminates the program immediately,

And that's what you want your client to see? Your library crashing the
whole program?
and with the aid of a debugger

Any plan to spend time in the debugger is a self-fulling prophecy.

Anyway, you're missing the point: The bug isn't in the OP's code, it's
in the client code, which he may not have, in which case he cannot run
in his debugger.
you can see the
whole stack trace and the values of the variables exactly when the error
happened. This way the programming error can be fixed, and the indexing
out of boundaries will not happen anymore.

By the time you see a stack trace, you're already working backwards.
The best tools for finding and tracking logical errors are compilers and
unit tests. It is uncanny how the people who are best with the debugger
are the worst developers. (That's not meant as a dig at you, btw; I
have no idea what your day-to-day code looks like, and I'm not in a
position to criticize it.)

Suppose you are using some library code, you pass it a bad value (we all
make mistakes), and then at run-time you see (shiver) an assertion
failure. The stack trace shows you where the error nominally occurred,
and what the call-stack was at the time. You didn't write the functions
at the top or the bottom of the stack trace, but you some of your own
code somewhere in the middle; you therefore crank up the debugger (you
poor, misguided soul) so that you can figure out where the root cause of
the error is. Until you figure out where the bad value originated, you
don't know whether or whither to direct your bug report. (You don't
know that the real problem is anywhere near where the assertion error
occurred, because the library is abusing assert() to serve as a prereq
check.)

To figure out where the error actually originated, you have to walk
through the code (starting where?) in the debugger, step by step, over
who knows how many LOC, until you see the assertion error
.. Then you usually have to do it again, because you still haven't found
the root cause, for the same reason you (or someone else) wrote
incorrect code in the first place. Stepping through code takes O(N)
time with the amount of code involved. It is quite possibly the single
least efficient way of finding and fixing errors that is still in common
use.
I can't even begin to imagine why throwing an exception instead, and
catching it somewhere else than right where the error happens, would be
a better idea.

The error goes to whomever believes they can catch it.
The only advantage of throwing an exception is that the program could,
if so designed (which is often *very* laborious), continue without
interruption.

But sometimes *very* [sic] necessary.
However, what would the program do in that case? A bug has
been detected,

An exception does not necessarily indicate a bug. It may just indicate
some input error, or other exceptional condition. (In the case of an
index being passed down, I agree that the index probably should have
been validated before an exception became necessary.)
and now the program knows that function is flawed, the
data is incorrect, and nothing that function returned can be relied on.

For better or worse, sometimes it has to. Suppose a plane's on-board
GPS software encounters an error. Should the whole on-board computer
just give up and let the plane drop from the sky? Of course not; it
should report to the error that the GPS is wonky, but do the best it can
to keep the plane in the air. This example is probably more extreme
than the OP's AppleCart, but the principle is the same. Once, while I
was working for a server company, our manager was very proud of our
product's nine-minute fail-over time. We then found out it wasn't good
enough, and I was cranky -- "What do they expect from us?" -- until I
found out that the servers were being used to route calls at an
emergency response center. Nine minutes are a long time to wait when
your child is choking on something. A crash is sometimes just not an
option, and post-mortem debug would not have been enough.

Client code seeing an assertion failure is a Very Bad Thing, even if no
one actually plummets to their death as a result. Even if the client
does something wrong (again: We all make mistakes), the least your
library can do is give them a chance to handle the exception.
That buggy function is completely useless.

You don't know that.
What exactly is the right course of action in this case?

Only the caller knows.
(And how does it differ from a simple assert?)

It gives the application an opportunity to handle the exception, as
opposed to aborting the program.
 
K

Kai-Uwe Bux

Jeff said:
I think red floyd already explained it as well as I could.


That may be the best place to for the error to be detected, but it's not
necessarily the right place for it to be handled. In particular, part
of the code you snipped showed that the index was originally passed to
the OP's function from some client. The error is almost certainly in
the client code, not the OP's class, so it is the client who needs to be
notified. Maybe the client would like to log the error but keep the
program running, or maybe the client would like to terminate the program
altogether. This is the not for the OP's class to decide.

It is for the OP to decide what the invariants of the class are and what the
contracts for its member functions should be. Once the contract is
published, it is the client code programmers task to deal with that. (Of
course, in a larger project, client code programmers might have particular
requests about how they would like the contracts to be worded.)

If the contract states that any input shall be accepted but certain inputs
be reported by an exception, so be it. If the contract states that certain
inputs are invalid and lead to undefined behavior, an assert() is the right
choice.
Nope. Assert is for documenting that a particular condition is
impossible.

You probably mean "unforseen". Impossible conditions could not happen.

Assert is frequently abused to verify prerequisites, but an
assertion failure really is, by definition, an internal error.

Assertions can be used to verify preconditions, i.e., to enforce the
contract of a routine. By definition, a violation of the contract does not
entitle the violating party to anything. In particular, there is no
requirement that the caller be notified.

Or, to say the same thing the other way around: if the caller is to be
notified by an exception, the input was not in violation of the contract
but the contract required a throw of an exception.


[snip]


Best

Kai-Uwe Bux
 
J

Jeff Schwab

Kai-Uwe Bux said:
It is for the OP to decide what the invariants of the class are and what the
contracts for its member functions should be. Once the contract is
published, it is the client code programmers task to deal with that. (Of
course, in a larger project, client code programmers might have particular
requests about how they would like the contracts to be worded.)

If the contract states that any input shall be accepted but certain inputs
be reported by an exception, so be it. If the contract states that certain
inputs are invalid and lead to undefined behavior, an assert() is the right
choice.

I have seen that view espoused before, and I disagree with it. Even if
crashing the program is deemed the best option, assert is exactly the
wrong way to achieve that end.
You probably mean "unforseen".

No, I mean "impossible." There is, again by definition, no way to
prepare for an unforeseen event. To the extent that you are preparing
for something, it is not unforeseen.
Impossible conditions could not happen.

Which is why assertions should never fail. If an assertion does fail,
then the condition was not impossible after all, and there is a bug in
the program.
Assertions can be used to verify preconditions, i.e., to enforce the
contract of a routine.

"Can" and "should" are two different things.
By definition, a violation of the contract does not
entitle the violating party to anything. In particular, there is no
requirement that the caller be notified.

If that is your philosophy, then why validate your input parameters at
all? There is valid code designed this way, but if you are bothering to
check the validity of your input, you can at least handle any errors as
gracefully as possible.
Or, to say the same thing the other way around: if the caller is to be
notified by an exception, the input was not in violation of the contract
but the contract required a throw of an exception.

If the contract requires an exception, then an exception must be thrown;
however, a contract violation that is not guaranteed to throw an
exception may throw one anyway, unless a specific no-throw guarantee is
in place (as is common for destructors).
 
K

Kai-Uwe Bux

Jeff said:
I have seen that view espoused before, and I disagree with it. Even if
crashing the program is deemed the best option, assert is exactly the
wrong way to achieve that end.


No, I mean "impossible." There is, again by definition, no way to
prepare for an unforeseen event. To the extent that you are preparing
for something, it is not unforeseen.


Which is why assertions should never fail. If an assertion does fail,
then the condition was not impossible after all, and there is a bug in
the program.

That is why I would say "unforseen". If an assertion fails it proves that I
failed to see that the case could happen. I put the assertion documenting
by believe that a certain path of execution would never be taken, but I do
so because I know I might be wrong.

But we agree on the substance: an assert() claims that a certain condition
is true and when it turns out to be false, there is a bug.

"Can" and "should" are two different things.


If that is your philosophy, then why validate your input parameters at
all? There is valid code designed this way, but if you are bothering to
check the validity of your input, you can at least handle any errors as
gracefully as possible.

I claim that for contracts that specify undefined behavior, an assertion is
more often than not the most graceful way of handling a violation:

a) The assertion can be eliminated in performance critical regions when the
code is considered program is considered debugged.

b) Aborting the program when a bug is encountered is often just the
RightThing(tm). If the program goes on although a bug has been detected,
the output cannot be trusted, which is often fatal. I really appreciate
when my compiler fails with an Internal Compiler Error to the compiler
producing bogus object code. I do see that there are classes of bugs that
can be handled differently: e.g., rendering bugs in games, where the
problem will go away after a few frames and aborting the game would
definitely make for a worse gaming experience. Whether an abort is graceful
or not is strongly related to whether and how correctness of output is
defined and how much it matters.

c) The contract does not specify which exception would be thrown. So what
should the caller catch?

If the contract requires an exception, then an exception must be thrown;
however, a contract violation that is not guaranteed to throw an
exception may throw one anyway, unless a specific no-throw guarantee is
in place (as is common for destructors).

Any exception that is thrown _should_ specified in the contract. Otherwise,
why should a caller provide a catch() clause? Uncaught exceptions are more
or less equivalent to asserts in that they unwinde the stack completely.


Best

Kai-Uwe Bux
 
J

James Kanze

<gasp> Strongly disagree. </>

Huh? You have code which you've just proven doesn't work, and
you want it to continue doing incorrectly whatever it was doing?

When you detect an "impossible" state in the code, the only
correct thing to do, nine times out of ten, is to abort the
program as soon as possible, rather than continue stumbling on,
without really knowing whether the results are correct or not.
(This obviously depends somewhat on the domain. In process
control, and especially with critical systems, not aborting
would almost amount to criminal negligence. At the other
extreme, in games programs, the worst thing that could happen if
you don't abort is that the program crashes, which comes out to
about the same, so aborting is probably wrong, at least in
released code. Most programs, however, are probably closer to
the first situation---they do something whose results matter,
and no results are better than incorrect results.)

[...]
Huh? The exception is *exactly* the right solution, for the
reasons red floyd already explained.

If you've detected a situation which can only be the result of a
programming error, i.e. if you've detected that some pre- or
post-condition or some invariant doesn't hold, then you can have
no confidence in whatever the program does from then on. In
such cases, the correct procedure is almost always to abort, so
that higher level corrective action can occur.
 
J

James Kanze

Could you please explain to me why is that?
If indexing out of boundaries at some place is an indication
of a programming error, ie. a bug, the best course of action
is to report immediately about this detected error, at the
place where it happens. assert() is exactly the tool designed
for this: It terminates the program immediately, and with the
aid of a debugger you can see the whole stack trace and the
values of the variables exactly when the error happened. This
way the programming error can be fixed, and the indexing out
of boundaries will not happen anymore.

Note that even without the possibilities of a debugger...

[...]
The only advantage of throwing an exception is that the
program could, if so designed (which is often *very*
laborious), continue without interruption. However, what would
the program do in that case? A bug has been detected, and now
the program knows that function is flawed, the data is
incorrect, and nothing that function returned can be relied
on. That buggy function is completely useless. What exactly
is the right course of action in this case? (And how does it
differ from a simple assert?)

That's the key point. If you can't count on doing anything
correct, the only course of action is not doing anything,
quickly and noisily, so that whatever back up systems are
available can take over. (The "back up system" might be as
simple as a human being deciding that we'll have to do without
that functionality for the moment.)
 
J

James Kanze

Because the correct place to catch the error is not in at(),
or in GetApple(), but rather in the caller of GetApple(), who
will have some sense of what to do with it.

And how will the caller of GetApple() have some sense of what to
do with it? If the argument is the result of a programming
error, and you can't logically isolate the error (and if there
is a programming error, it means that your reasoning about the
program was wrong, so you can't logically say anything about the
program), then there is no place in the code where you can have
some sense of what to do with the error. The only thing to do
is to "propagate" the "exception" somewhere outside of the
corrupted process. Which is really what an assertion failure
does: it is an "exception" which can only be caught and handled
outside the process. (Outside the process, of course, might
even be outside the machine, e.g. a human operator.)
 
J

James Kanze

I think red floyd already explained it as well as I could.

I didn't see where he explained anything except how an exception
works.
That may be the best place to for the error to be detected,
but it's not necessarily the right place for it to be handled.

That's not what he said. He said it's the best place to report
the error. Where you have a complete stack trace and a maximum
of other information. Anything you do after detecting the error
may loose information or degrade the situation.
In particular, part of the code you snipped showed that the
index was originally passed to the OP's function from some
client. The error is almost certainly in the client code, not
the OP's class, so it is the client who needs to be notified.

Let's see if I've got this right. The client code is hosed, to
the point of provenly being incapable of even providing a
correct argument, and you're saying that it's the most
trustworthy place for the error to be handled. There's
something that I don't understand there. The exception *must*
propagate at least beyond the client code which was corrupted.
Without executing any code in the corrupted client. Including
destructors.

That's sounds like abort, to me. It's certainly not exceptions.
Maybe the client would like to log the error but keep the
program running, or maybe the client would like to terminate
the program altogether. This is the not for the OP's class to
decide.

The client has proven himself incapable of deciding. Someone
has to decide. By aborting, you push the decision up to a
higher level.
Nope. Assert is for documenting that a particular condition
is impossible.

Exactly. And the impossible has just happened. So all bets are
off.
Assert is frequently abused to verify prerequisites, but an
assertion failure really is, by definition, an internal error.

And calling a function while failing to meet the preconditions
isn't an interal error?
And that's what you want your client to see? Your library
crashing the whole program?

Better that, than silently giving a wrong results. Maybe
causing the rods to be pulled out of the reactor, and resulting
in a nuclear meltdown. (My view of this may be prejudiced
because I've worked on critical systems in the past. I
particularly remember the locomotive brake system, where the
emergency brake system which was used when our system detected
an error actually cut all power to the processor. They weren't
taking any chances of our doing something wrong.)
Any plan to spend time in the debugger is a self-fulling prophecy.
Anyway, you're missing the point: The bug isn't in the OP's
code, it's in the client code, which he may not have, in which
case he cannot run in his debugger.

I think you're missing the point. The error is somewhere in the
process. We don't know where, but we can no longer count on the
process doing the right thing.
By the time you see a stack trace, you're already working
backwards. The best tools for finding and tracking logical
errors are compilers and unit tests. It is uncanny how the
people who are best with the debugger are the worst
developers. (That's not meant as a dig at you, btw; I have no
idea what your day-to-day code looks like, and I'm not in a
position to criticize it.)

Debuggers are useful for post-mortems. A stack trace. That's
about it, but that's still something. (That's not strictly
true. I actually had a case the other day where I found the
debugger was really useful on running code. First time in about
twenty years.)

I think you're putting too much emphisis on the debugger part.
The important aspect is that if you couldn't count on the client
code giving you a correct argument, how can you count on it
doing correct error handling.
Suppose you are using some library code, you pass it a bad
value (we all make mistakes), and then at run-time you see
(shiver) an assertion failure. The stack trace shows you
where the error nominally occurred, and what the call-stack
was at the time. You didn't write the functions at the top or
the bottom of the stack trace, but you some of your own code
somewhere in the middle; you therefore crank up the debugger
(you poor, misguided soul) so that you can figure out where
the root cause of the error is. Until you figure out where
the bad value originated, you don't know whether or whither to
direct your bug report. (You don't know that the real problem
is anywhere near where the assertion error occurred, because
the library is abusing assert() to serve as a prereq check.)

That's a fact of life. I've had to handle assertion failures
which were ultimately due to an uninitialized pointer in some
totally unrelated code. The clients data were completely hosed.
To figure out where the error actually originated, you have to
walk through the code (starting where?) in the debugger, step
by step, over who knows how many LOC, until you see the
assertion error.

No. You start by reasoning about the error. And by going to
the log, and seeing what happend before. If the error is caused
by data corruption (all too often the case), you then try and
reproduce it. Until you can reproduce it, you can't fix it.

Generally, once I've determined the cause of the error, from the
stack walkback, I don't use the debugger any more. But that's
really not the issue. The point I think Juha was making is that
if the client code catches the exception, and masks it, you
can't even determine what the cause was, so you don't really
have the information necessary to begin trying to reproduce it.
In the worst case, the error disappears completely, the program
outputs a wrong result, and nobody is even aware of it.
Then you usually have to do it again, because you still
haven't found the root cause, for the same reason you (or
someone else) wrote incorrect code in the first place.
Stepping through code takes O(N) time with the amount of code
involved. It is quite possibly the single least efficient way
of finding and fixing errors that is still in common use.

It's true that just ignoring them, and using the wrong results,
requires less effort on the part of the developers.
The error goes to whomever believes they can catch it.

And you trust them, given that they're also the ones who
provided the wrong argument in the first place.
But sometimes *very* [sic] necessary.

Usually, such aspects are handled as a system level, outside of
the process. (At least, I've never seen a system in industry
where they weren't, and the same thing has held for all of the
server software in the commercial applications I've seen. About
the only exception to this rule has been light weight GUI front
ends, which don't calculate or decide anything, but just
display.)
An exception does not necessarily indicate a bug.

It shouldn't ever indicate a programming error. That's not its
role.
It may just indicate some input error, or other exceptional
condition. (In the case of an index being passed down, I
agree that the index probably should have been validated
before an exception became necessary.)

Which is all Juta is saying. It's hard to imagine a case where
an exception is the desired behavior for an array bounds error.
For better or worse, sometimes it has to. Suppose a plane's
on-board GPS software encounters an error. Should the whole
on-board computer just give up and let the plane drop from the
sky?

The whole on-board computer should just give up, noisily, so
that the backup system can take over, and so that in the worst
case, the pilot knows that he cannot count on it, and resorts to
some alternative. This is much preferable to a system which
informs the pilot that he has 1000 ft altitude, and should
descend 500 ft in the landing approach, when he's really only
200 ft above the ground.
Of course not; it should report to the error that the GPS is
wonky, but do the best it can to keep the plane in the air.

Have you ever actually worked on such systems? In the end, it's
the pilot's responsibility to keep the plane in the air, and
anytime the software isn't sure of doing the right thing, it
should abort, letting the backup systems take over (where the
ultimate backup system is the pilot). In such cases, giving
wrong information or doing the wrong thing is worse than giving
no information or doing nothing.
This example is probably more extreme than the OP's AppleCart,
but the principle is the same. Once, while I was working for
a server company, our manager was very proud of our product's
nine-minute fail-over time. We then found out it wasn't good
enough, and I was cranky -- "What do they expect from us?" --
until I found out that the servers were being used to route
calls at an emergency response center. Nine minutes are a
long time to wait when your child is choking on something. A
crash is sometimes just not an option, and post-mortem debug
would not have been enough.

Many of the systems I've worked on in the past have had
contractual penalties for down time. It's fairly usual
procedure in many fields.
Client code seeing an assertion failure is a Very Bad Thing,
even if no one actually plummets to their death as a result.

Not seeing an assertion failure when the program is wrong is an
almost sure guarantee of the plane doing something wrong.
Even if the client does something wrong (again: We all make
mistakes), the least your library can do is give them a chance
to handle the exception.
You don't know that.

You don't know anything about it. You can't take chances.
Only the caller knows.

You do know that the caller isn't behaving correctly. How can
you count on him doing the right thing in terms of error
recovery, when he wasn't capable of doing the right thing when
he passed you the arguments? Has he somehow, miraculously,
fixed himself.
It gives the application an opportunity to handle the exception, as
opposed to aborting the program.

The error must be propagated up to a point outside of the
process. That's the only place where there's a reasonable
chance of it being handled correctly. (Note that most systems
or applications---and all critical systems and
applications---consist of more than a single program.)
 
J

Juha Nieminen

I couldn't have responded better than James did. One note, though:

I honestly can't understand this opinion.

Developers are humans, and humans make mistakes. No matter how
experienced you are at developing, even if you are the best C++
developer in the world and your code has the best quality in the world,
you will make small mistakes here and there from time to time.

The vast majority of these small mistakes can be found with a proper
debugger almost immediately. You simply have to see the line where the
program crashed in order to immediately see your own mistake and fix it.
Without the aid of a debugger it could take tens of minutes, or even
hours at worst. ("Segmentation fault" is not a very informative error
message. Having to find the place where the fault happens by adding
debugging prints to your program can be a real pain.)

If the error is not exactly at the line where the crash happened, the
debugger is even more useful, exactly because of the stack trace. You
can navigate the call stack down until you find the actual place where
the error happened, you can easily examine the values of the variables
at that place, and in the majority of the cases you will immediately see
what the problem was (usually a small typo or thought mistake).

It is, of course, possible to have really nasty bugs which are
extremely hard, or even impossible, to find with just a debugger.
However, that doesn't mean that the debugger isn't useful.

If I had to develop C++ programs without any kind of debugger, it
would be a real pain. Each small mistake, each small typo, would require
a long and laborious task of manually adding debug prints to try to
binary-search the location of the error... Horrible.
(I have actually had to do this in the past, when developing programs
in a Unix environment using gcc and without gdb or any other kind of
debugger. It was not nice.)
 
I

Ian Collins

Juha said:
If I had to develop C++ programs without any kind of debugger, it
would be a real pain. Each small mistake, each small typo, would require
a long and laborious task of manually adding debug prints to try to
binary-search the location of the error... Horrible.

There is a school of thought that I am becoming more aligned with as my
TDD skills improve that says using a debugger on new code is a sign
flaws in your development process.

I try avoid the debugger wherever possible, it simply slows me down.
Better to make a small change, run the tests. If a test fails, revert
the change and do it again another way. Debugging with a debugger is
one of those intense processes that can suck up a lot of time before you
realise ad it disrupts the development flow.

I started working this way while building a complex PHP application, I
never did find a decent PHP debugger, so I became a much more
accomplished test writer.
 

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,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top