Boost scoped_ptr design question

J

James Kanze

Why do the operations of scoped_ptr use undefined behavior instead of
throwing?

scoped_ptr is designed to emulate a pointer; raw pointers have
undefined behavior, so so does scoped_ptr. (One can argue
whether this is a good thing or not, but nothing in undefined
behavior prevents an implementation from doing the right thing,
e.g. inserting an assert.)

Throwing an exception is, of course, the wrong thing. If you
discover a programming error, you should abort (in most
applications, anyway---there are exceptions).
 
G

gwowen

scoped_ptr is designed to emulate a pointer; raw pointers have
undefined behavior, so so does scoped_ptr.  

Throwing an exception is, of course, the wrong thing.  

One wonders what std::logic_error is for, then: "The class logic_error
defines the type of objects thrown as exceptions to report errors
presumably detectable before the program executes, such as violations
of logical preconditions or class invariants."

At the very least, you can catch std::logic_error at the top level and
attempt emergency shutdown. If your code is operating an X-ray
machine, the patient will probably be grateful that the power gets cut.
 
J

James Kanze

On 15/12/2010 15:01, James Kanze wrote:
If you discover a programming error you should fix the programming
error.

Totally agree, but it's rather difficult to do so from within
the code:). Crashing probably causes it to get fixed faster
than any other behavior.
Out of bounds std::vector::at() throws an exception; it doesn't
abort. Out of bounds std::vector::at() is a programming error.

No. std::vector<>::at() has defined semantics in the case of
out of bounds; an out of bounds index is not a precondition
failure (like it is with std::vector<>::eek:perator[]). I've never
found any real use for std::vector<>::at() in my own code, but
apparently someone once thought it useful.
 
J

James Kanze

One wonders what std::logic_error is for, then: "The class logic_error
defines the type of objects thrown as exceptions to report errors
presumably detectable before the program executes, such as violations
of logical preconditions or class invariants."

One does wonder, yes.
At the very least, you can catch std::logic_error at the top level and
attempt emergency shutdown. If your code is operating an X-ray
machine, the patient will probably be grateful that the power gets cut.

If you're controlling an X-ray machine or anything like that,
you must abort at the slightest hint of a problem, executing the
least code possible. Who says that unrolling the stack will cut
the power---the code has done something wrong, the internal
state is incoherent, and executing the destructors could
possibly increase the dose by a couple of orders of magnitude.
Where as crashing causes the emergency handling (backup, etc.)
to come into play, which does ensure that the X-rays are turned
off.
 
G

gwowen

Where as crashing causes the emergency handling (backup, etc.)
to come into play, which does ensure that the X-rays are turned
off.

Ah, but what if you're the poor sap who's writing the emergency
handling? :)
You can't keep aborting and hope there's another layer of backup...
 
B

Balog Pal

One wonders what std::logic_error is for, then: "The class logic_error
defines the type of objects thrown as exceptions to report errors
presumably detectable before the program executes, such as violations
of logical preconditions or class invariants."
At the very least, you can catch std::logic_error at the top level and
attempt emergency shutdown. If your code is operating an X-ray
machine, the patient will probably be grateful that the power gets cut.

I'd wonder in a different context, but it is the C++ standard lib, here
anything well designed and sensible would state the exception, and having
fluff like that is the default, unfortunately.

I personally yet to see anyone throwing logic_error, that is the good side.
:)
 
B

Balog Pal

James Kanze said:
If you're controlling an X-ray machine or anything like that,
you must abort at the slightest hint of a problem, executing the
least code possible.

Just don't forget to make the system stop the rays somehow.
Who says that unrolling the stack will cut
the power---the code has done something wrong, the internal
state is incoherent, and executing the destructors could
possibly increase the dose by a couple of orders of magnitude.

Or just delay the watching supervisory process to detect the problem and
issue the said shutdown...
Where as crashing causes the emergency handling (backup, etc.)
to come into play, which does ensure that the X-rays are turned
off.

Yeah.

(beyond the rays, moving the C-arm is about as fun if getting out of
control)
 
B

Balog Pal

Ah, but what if you're the poor sap who's writing the emergency
handling? :)
You can't keep aborting and hope there's another layer of backup...

In that application you keep the state at minimum. Avoiding all kind of
situations a logic error, or anything else (including resource allocations,
etc.) could enter the picture.
 
B

Balog Pal

Leigh Johnston said:
I would actually be rather worried if I knew the control software of an
X-ray machine I was lying under was written in C++. Why? C++
programmers. :)

Some of it is actually wrinnten in C++. I guess majority is written in C.
The latter is worse by a big deal. Provided you have actual sw. engineers
at helm. If not, you're doomed all the same.
 
B

Balog Pal

Leigh Johnston said:
I throw std::logic_error. I do not catch std::logic_error. The program
aborts.

And that is better than direct call to terminate() on the spot how?
 
I

Ian Collins

It is no better and no worse; it does potentially provide more
information: one could potentially catch the logic_error at main() (or
equivalent), print out the associated error string and then re-throw for
example; I don't do this however; I just rely and the default behaviour
of calling terminate/abort.

By throwing the exception you loose all of the state information at the
point where you detected the error. You also unwind the stack, which
may end up doing more harm.
 
B

Balog Pal

Leigh Johnston said:
It is no better and no worse; it does potentially provide more
information: one could potentially catch the logic_error at main() (or
equivalent), print out the associated error string and then re-throw for
example; I don't do this however; I just rely and the default behaviour of
calling terminate/abort.

IIRC the mandated behavior for a thrown, not caught exception is "call
terminate, before that stack unwind may or may not happen". So the
difference is in the quoted "may".

If someone upstream decides to catch the exception, even just to re-throw or
call terminate there after emitting some smoke signals, stack unwinding
becomes mandatory.

In my book that means that unknown amount of program code is allowed to
execute after the point of discovery that the program state is foul. (I hope
we did agree earlier that throwing logic_error is done on that discovery...)

It is not something I feel safe, ot could sign off as "I know it will be
okay". Let's assume I have some hardened log component, I could live with a
direct call to it delegating some info -- that is at least something I know
and may evaluate the risks. While the stuff on the stack above me is beyond
the reach.
 
M

Marc

James said:
scoped_ptr is designed to emulate a pointer; raw pointers have
undefined behavior, so so does scoped_ptr. (One can argue
whether this is a good thing or not, but nothing in undefined
behavior prevents an implementation from doing the right thing,
e.g. inserting an assert.)

Throwing an exception is, of course, the wrong thing. If you
discover a programming error, you should abort (in most
applications, anyway---there are exceptions).

"most applications"? Can you qualify that? When you say "most" without
qualifying it, then the referrent set of applications is ALL
applications, from the one in that nifty Star Trek watch to the GUI on
your desktop (not that I am suggesting that those 2 examples really
define endpoints).
 
M

Marc

James said:
One does wonder, yes.


If you're controlling an X-ray machine or anything like that,
you must abort at the slightest hint of a problem, executing the
least code possible. Who says that unrolling the stack will cut
the power---the code has done something wrong, the internal
state is incoherent, and executing the destructors could
possibly increase the dose by a couple of orders of magnitude.
Where as crashing causes the emergency handling (backup, etc.)
to come into play, which does ensure that the X-rays are turned
off.

"the slightest hint of a problem" must come from some kind of monitor
that is separate from the program, for any more instruction execution by
the errant code could do more damage. abort() is not any more magical
than unwinding is. Agree?
 
B

Balog Pal

Leigh Johnston said:
std::vector::at throws std::eek:ut_of_range which is-a std::logic_error.

I only use [] of vector and just like James never found any use of at() in
the industrial environment.

And being std:: at '98 maps to more than 50% to be something between bad and
suboptimal. :( I'd sure never use std:: stuff as good example for anything.
 
B

Balog Pal

Marc said:
"most applications"? Can you qualify that? When you say "most" without
qualifying it, then the referrent set of applications is ALL applications,
from the one in that nifty Star Trek watch to the GUI on your desktop (not
that I am suggesting that those 2 examples really define endpoints).

My exception list is ~ "those you do not put under any kind of quality
control", IOW have no requirements/expectations on quality. You know,
provided "as is", supplier can only state his total unresponsibility for
anything.
 
M

Marc

Leigh said:
It is not compulsory for an implementation to unwind the stack when an
unhandled exception is thrown however I agree that possible stack
unwinding may be unwise in safety critical software.

Which is to take a stance opposite to James's, but uncertain until he
replies again. I think the best/correct answer will have to come from
someone who actually does use C++ in safety/life-critical systems. That
will satiate the need to know and stop all the hypothesizing. Or maybe
C++ is not used in any of those systems? It doesn't matter what they use,
it's the design pattern that is in question, not the specific
implementation of it. Hopefully we will be enlightened! (In more ways
than one too). I certainly want to know.
 
B

Balog Pal

Leigh Johnston said:
std::string::append can also throw std::eek:ut_of_range which is-a
std::logic_error; I am sure there are plenty of other examples of the
standard library throwing exceptions which are derived from
std::logic_error.

If it is fine for the C++ standard library to throw std::logic_error then
it is fine for code which uses the C++ standard library to throw
std::logic_error; horse already bolted etc.

That is a piece of weird logic.
for one, std:: does not throw the said exception on a whim. It does only for
well defined conditions. You can use all operations of std::string, just
avoid those conditions, and can be sure never to get out_of_range thrown,
ever.

And the realistic approach to std:: is to use just parts of it in any case.
 
M

Marc

Leigh said:
You want to run as little code within the context of the errant
process as possible when dealing with errors in safety critical
systems; abort can therefore be seen as the more appropriate action
rather than stack unwinding for such systems. Different applications
require different degrees of defensiveness; write code (and coding
standards) accordingly.

I've started another thread for this interesting topic. It really has two
parts: What are the accepted designs for these systems?; How does that
map onto, or what does it mean in regards to C++? Please redirect your
discussion to the new thread, thank you.
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top