Boost scoped_ptr design question

M

Marc

Marc said:
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.

I forgot to say that the new thread is: "Is C++ used in life-critical
systems?"
 
M

Marc

Marc said:
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.

Please redirect all thoughts on this to the new thread: "Is C++ used in
life-critical systems?". Thank you.
 
I

Ian Collins

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.

It is, but that depends on the requirements for the application.

The standard library has it's own set of requirements and I guess it was
deemed inappropriate for a general purpose library to abort on out of
range conditions. The user can choose to abort by not catching
std::logic_error, so the choice is passed back to them.
 
B

Balog Pal

Ian Collins said:
It is, but that depends on the requirements for the application.

The standard library has it's own set of requirements and I guess it was
deemed inappropriate for a general purpose library to abort on out of
range conditions. The user can choose to abort by not catching
std::logic_error, so the choice is passed back to them.

And it is no problem to wrap the logic_error emitting calls -- either with a
condition check or a try block -- thus mitigating the 'execute unknown
amount of code' problem.

IMO keeping the index IN-RANGE is no black magic either if you actually have
design in the software and some quality measures.
 
B

Balog Pal

Leigh Johnston said:
What? Don't talk nonsense. I use most of the standard library.

For example I never used std's allocator. Or codecvt, locale. custom
streambuf. Quite sure will never use them in my life.

Some stuff I used only as temporary measure before importing proper
libraries: bind1st, bind2nd, auto_ptr.

Don't recall ever actively using: deque, priority_queue, reverse_iterator,
complex, valarray, slice

Braindead stuff I use and damn on regular basis: string, map.
 
B

Balog Pal

Leigh Johnston said:
How is what parts of the standard library you happen to use relevant to
anything?

I thought you'll comment either 'I use all of those' or 'well, me neither'.
:)
 
I

Ian Collins

For example I never used std's allocator. Or codecvt, locale. custom
streambuf. Quite sure will never use them in my life.

Some stuff I used only as temporary measure before importing proper
libraries: bind1st, bind2nd, auto_ptr.

Don't recall ever actively using: deque, priority_queue,
reverse_iterator, complex, valarray, slice

Braindead stuff I use and damn on regular basis: string, map.

What's wrong with std::vector and std::map? I'm sure most C++
programmers use them on a daily basis without complaint.
 
B

Balog Pal

Ian Collins said:
What's wrong with std::vector and std::map? I'm sure most C++ programmers
use them on a daily basis without complaint.

vector is about the only thing in std I'd say is okay as is. (certainly we
all had everything it offers well before the standard even was considered.)

map has a broken interface:
- operator[] has no const variant
- operator[] that is there mutates the collection inserting the key with a
def-constructed value, that is a source of many bugs
- insert and iteration over map uses std::pair, that makes client code
unreadable. And mostly unusable with algos that are present in std:: -- I
had to write a full suite of their dupes that act on map key or map value...

In summary, for almost all operations involvng std::map I use some wrappers,
be it insert, lookup to tell presense, lookup to fetch existing element,
iteration.
 
J

James Kanze

On 15/12/2010 19:29, Balog Pal wrote:
It is no better and no worse; it does potentially provide more
information:

Or less. On Unix systems, if you call abort, you get a core
dump, and can do a post-mortem. On Windows systems, you can
configure the system (I think) so that abort pops you into the
debugger (not much use if your code is running on a client's
machine, I know). In either case, the stack has not been
unwound, and you can look at any number of stack variables. If
you throw, you loose, or might loose, stack context.

There is no one universal solution. Globally, I'd vote for
abort() in most situations, but in my current software, we throw
(and use compiler options to convert hardware traps, like
illegal accesses, to C++ exceptions). In this particular case,
throwing is the right solution, even if it isn't in most cases.
 
J

James Kanze

Which is to take a stance opposite to James's,

Maybe. Leigh has not said that he's working on safety critical
software. There is no "always right" answer. By default, it's
probably best to abort, because this is the "safest" solution.
But there are certainly exceptions, and if Leigh (or his
company) have analysed the issues, and determined that throwing
is the right solution in the context they're working in, then
throwing is the right solution.
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.

For critical systems (I've worked on quite a few), the answer is
always to shut down as soon as possible, executing as little
code as possible, anytime an anomaly is detected. I don't think
there's any question about that. But not everyone is working on
a critical system. (We throw in my current application, and
that's the correct solution for this particular case.)
 
J

James Kanze

What's wrong with std::vector and std::map?

std::vector doesn't guarantee bounds checking. The way
iterators work is a bit awkward, to say the least (but I guess
you could use std::vector without using iterators). And it's
all too easy to accidentally invalidate an iterator (and have
the code pass all of your tests, because you've invalidated it
by doing push_back into a very large vector, and the probability
of it requiring a reallocation is low). And certainly, for many
(most?) uses, a hash table would be preferable to std::map (but
in this case, I understand why the standard didn't use one).
I'm sure most C++
programmers use them on a daily basis without complaint.

They're there. They work. Most importantly, you can (or should
be able to) expect any new hire with C++ experience to know them
already. Those are powerful pluses; enough to outweigh the
minuses most of the time.

The completeness of the library is also an argument. I (and no
one I've worked with) likes the fact that you need two iterators
to do anything. But we learn the idiom, and use it, because
there's so many useful things in the standard library that
require it. (When I have to design a new container, with an
iterator, I make sure that the iterator supports both the STL
and the GoF iterator idioms. The GoF idiom is a lot easier to
use, and a lot more flexible, but there's so much which uses the
STL idiom, you can't avoid it.)
 
J

James Kanze

On 15/12/2010 23:46, Balog Pal wrote:
Ian Collins said:
Braindead stuff I use and damn on regular basis: string, map.
What's wrong with std::vector and std::map? I'm sure most C++
programmers use them on a daily basis without complaint.
vector is about the only thing in std I'd say is okay as is. (certainly
we all had everything it offers well before the standard even was
considered.)
map has a broken interface:
- operator[] has no const variant
What would a const operator[] do if the element doesn't exist?
Throw an exception? Not very user friendly.

What does the built-in operator[] do (on a C style array)?
Undefined behavior, I'd say.

In practice, operator[] isn't that useful on map. Big deal:
it's really a case of operator overloading abuse anyway.
- operator[] that is there mutates the collection inserting
the key with a def-constructed value, that is a source of
many bugs
Then use insert.

Or anything else. If function x doesn't do what you want, use
something else.
Not true; I use std::map with std algorithms with no problems; you
simply have to except that a std::map's value_type is a pair.

Certainly. You can live with just about anything. But that
doesn't mean that it couldn't be cleaner.
I have wrapped std::map with a container called "mutable_set"
but this is so you can have a something similar to std::set
but with elements you can mutate; it is not intended as
a replacement for std::map whose interface is fine when you
want "map semantics" (IMHO).

I think most of the standard containers are designed to be low
level building blocks. I think it has to be this way: there is
no one interface for map which is appropriate for all high level
uses.
 
M

Miles Bader

James Kanze said:
std::vector doesn't guarantee bounds checking.

That's one of its strengths too, of course -- if std::vector _did_
guarantee bounds-checking it would probably get used much less often,
because people would always be thinking "hmm, if I wedge in a raw array/
pointer here, my indexing in the loop will be faster..."

The fact that std::vector indexing ends up being more or less as fast as
more primitive mechanisms in the inner loop, and yet offers additional
safety / flexibility / robustness is a powerful incentive to use it...

-Miles
 
J

James Kanze

"most applications"? Can you qualify that?

Not really. "Most" is "most", a relatively vague word
(intentionally). Concretely, I don't know how to count
"applications", so I can't provide anything more precise. But
globally, the cases where not aborting is appropriate seem to be
exceptions to the general rule, and very much in a minority.
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).

Games are definitely an exception to the rule, and game software
should probably throw (and catch at a higher level, and try to
recover). If the coding error has not caused damage, or the
damage was very local, the player may not even notice the
glitch, and otherwise, the game experience is the same as if
you'd aborted. The same thing probably holds for software which
is only "browsing"; which doesn't modify data (has no files open
for writing, other than logs or temp files, etc.). As soon as
the software modifies persistent data, or has some sort of
"behavior", you have to weigh the possible harm continuing might
do; in such cases, it's almost never appropriate to do anything
else but abort. And of course, in any critical application,
there will be some sort of redundancy or backup, and the rule is
to terminate the software as quickly as possible, executing as
little additional code as possible.
 
A

Alexei Zakharov

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. :)

It takes one to know one! :)
 
B

Balog Pal

James Kanze said:
Games are definitely an exception to the rule, and game software
should probably throw (and catch at a higher level, and try to
recover).

Crashing games are annoying. But games that mess up the save files are even
more so. And "recovery" so often lead to saves that stopped working a few
hours later, making you lose dozens of hours -- or just lead to uninstall
and blacklisting the company.

Certainly depends on "situation", in a game there can be many situatuions
that are not coming from undefined behacior or messed up state, just not
thinking some interaction of events. Where recovery is possible at cost of
losing some pixels on the screen. IMO those are not matching the original
line of logic errors we discussed.

(OTOH I see that game programmers reaching 2010 are still fighting trivial
issues like memory leaks. And management that dumps pre-beta stage into
release. See 'Elemental war of magic' for a recent example. :-((( )
If the coding error has not caused damage, or the
damage was very local, the player may not even notice the
glitch, and otherwise, the game experience is the same as if
you'd aborted. The same thing probably holds for software which
is only "browsing"; which doesn't modify data (has no files open
for writing, other than logs or temp files, etc.). As soon as
the software modifies persistent data, or has some sort of
"behavior", you have to weigh the possible harm continuing might
do; in such cases, it's almost never appropriate to do anything
else but abort.

My estimate for no-mutabe-state software is pretty low.
 
B

Balog Pal

James Kanze said:
std::vector doesn't guarantee bounds checking. The way
iterators work is a bit awkward, to say the least (but I guess
you could use std::vector without using iterators). And it's
all too easy to accidentally invalidate an iterator (and have
the code pass all of your tests, because you've invalidated it
by doing push_back into a very large vector, and the probability
of it requiring a reallocation is low).

Most STL implementations have pretty good diag support. Unfortunately it is
not that easy to use -- you may be forced to build the whole project with
special settings -- but tests then can flag many such mistakes.

iterator/reference invalidation is certainly a property of vector, but it is
not part of misdesign by any means -- and the engineer shall chose the
proper collection type with knowledge of that. Node-stable collections are
more hassle to use, but we chose those if invalidation is not contained in
the design.
They're there. They work. Most importantly, you can (or should
be able to) expect any new hire with C++ experience to know them
already. Those are powerful pluses; enough to outweigh the
minuses most of the time.

At least that is the common belief. What puts too much inertia agaist
introducing some better fitting thingy. And the more shame to those who
dumped this low quality thing on the world just because we demanded speed of
standardisation. (myself included. much regret)
The completeness of the library is also an argument. I (and no
one I've worked with) likes the fact that you need two iterators
to do anything.

The iterator concept in STL is just broken. I could not put my finger on it
how -- until Alexandrescu summarized it properly. The fundamental design of
them started from 'a plain pointer must be a first class random access
iterator'. Instead of principles around the iterator as design pattern (say
in GOF).
But we learn the idiom, and use it, because
there's so many useful things in the standard library that
require it.

Are they really that useful? I have a suite of algos that thake a
collection as argument -- and found to use almost exclusively those.
Dealing with sub-ranges in a collection appears to be just very rare. (and
where it isn't, say strings, I never thought using iterators in the first
place.)
(When I have to design a new container, with an
iterator, I make sure that the iterator supports both the STL
and the GoF iterator idioms. The GoF idiom is a lot easier to
use, and a lot more flexible, but there's so much which uses the
STL idiom, you can't avoid it.)

That sounds like 'lock-in' to stuff you also recognised to be less than
good.
 
B

Balog Pal

Leigh Johnston said:
Braindead stuff I use and damn on regular basis: string, map.

What's wrong with std::vector and std::map? I'm sure most C++
programmers use them on a daily basis without complaint.

vector is about the only thing in std I'd say is okay as is. (certainly
we all had everything it offers well before the standard even was
considered.)

map has a broken interface:
- operator[] has no const variant

What would a const operator[] do if the element doesn't exist? Throw an
exception? Not very user friendly.

I could live with UB. mandated throwing any of the std:: exceptions too.
When I use that, I know from design the element IS there. And I absolutely
do not want it created as a side effect of retrieval.

And a late comment to some design history, std::vector had NO specification
to hold continuous storage, and thus be compatible with old-style arrays
despite that being the intent. Thge fix was issued through defect report
(making into the standard 5 years later).

std::string was supposedly designed to be internally ref-counted in the
implementation. It was too until it turned out as broken due to some public
interface functions, and was forced to be deepcopying or lose
thread-safety.
 
B

Balog Pal

Leigh Johnston said:
What would a const operator[] do if the element doesn't exist? Throw
an exception? Not very user friendly.

I could live with UB. mandated throwing any of the std:: exceptions too.
When I use that, I know from design the element IS there. And I
absolutely do not want it created as a side effect of retrieval.

If the element IS there then no default construction and element creation
will happen so the non-const operator[] is fine. It is true I agree that
the requirement that the element be default constructible might be a pain
though.

huh? I said there is no const version. The code will just not compile and
that is it. Go directly to your own wrapper doing find. The stock interface
is only good to write textbook examples.
 

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

No members online now.

Forum statistics

Threads
473,785
Messages
2,569,624
Members
45,318
Latest member
LuisWestma

Latest Threads

Top