From: James Kanze on
PeteK wrote:
> James Kanze wrote:
> > > PeteK wrote:
> [snip]
> > > Note that the issue only affects a few classes. Most objects do
> > > not have (or at least don't need) a deterministic lifetime.

> I see this comment a lot, but I suspect that people think that the only
> objects that require deterministic lifetimes are those that manage
> external resources.

Not at all. Entity objects often have explicit lifetimes; when
a client disconnects from my server, the lifetime of the object
representing the connection ends.

Very, very few classes actually manage resources; I'd expect one
per type of resource, and there aren't that many types of
resources.

> However they tend to forget that it is equally
> important that when let logical owner of an object kills it off then
> reading or writing to it is also an error.

My experience is that almost no classes have a logical owner.
Most classes which have a deterministic lifetime manage that
lifetime themselves. When I'm using garbage collection in C++,
I'd guess that about 90% of the deletes are "delete this".

Almost by definition, of course, value objects don't have
explicit lifetimes---what's the lifetime of the constant pi, for
example. Of course, you normally pass value objects by value
(in C++), but if the actual size of the value varies, dynamic
memory is involved. Correctly designed, garbage collection can
make the implementation of such objects considerably simpler and
safer.

[...]
> > > But at that point, why bother with the extra work. I don't
> > > understand your point. If you're running a garbage collector,
> > > why not use it generally. Take advantage of it, and save
> > > yourself some work.

> I've nothing agains GC as the base-level memory manager, I just prefer
> to explicitly manage the lifetimes of all my classes etc.

> I know that you and Andrei appear to have lots of pointer cycles in
> your code,

What makes you think that? I know I have some: I much prefer
double linked lists, for example, to single linked ones (and a
double linked list implies cycles). In practice, bidirectional
navigation in entity objects is often required as well; the back
office needs to know which trades are affected to which client
orders, and the sales people start from the client order, to
find the trades affected to it. Real applications model real
world situations, and in the real world, bidirectional
navigation is essential.

> >> > > The thing is that all objects have a logical lifetime.

> > > Nonsense. What's the logical lifetime of the char[] which
> > > contains the characters in a string? In fact, very few objects
> > > have a logical lifetime.

> The logical lifetime is generally bound to the logical lifetime of the
> string (if we skip read-only slicing etc.). The logical lifetime of the
> string is bound to the object that contains it or the block of code
> that uses it.

"abc" is "abc", regardless of scope or context. You're letting
implementation constraints of C++ color your conception.

> In C++ we can extend that logical lifetime by using
> smart pointers and the like, but there is still a defined point when
> the object is logically dead.

Yes. When no other object can possibly access it. Actually,
something like a string or a set of integers isn't even
logically dead then, but of course, it doesn't matter. If we
can't access it, there's no point in keeping it around.

> If we we write a logically identical program in Java then the
> logical lifetimes of the objects should be identical.

It will be.

> Accessing logically dead data then becomes an error.

Accessing logically dead data is an error. In most cases, of
course, garbage collection ensures that this error can't occur.

> In Java you can only detect the error if you instrument the
> objects yourself. In C++ you have that choice, but you also
> have the opportunity to the the runtime system/specialist
> tools detect the problem too.

> >> > > Accessing them
> >> > > after their logical life is over is an error. Java choses to
define
> >> > > this as "not an error" (although this is probably more to do with
Java
> >> > > having GC). While it might appear that a string's char array
doesn't
> >> > > require a specific lifetime, if you've somehow acquired a pointer
into
> >> > > it then the array is kept alive long after the string is dead.

> > > What does that mean, after the string is dead? The string is
> > > never "dead", in any real sense of the word. At some point, it
> > > ceases to be accessible, but it's not logically dead.

> But this is the point. Logical lifetime and accessibility are not the
> same. If they were you would never get the dangling pointer problem.

True, but in practice, you don't have to worry about objects
which aren't logically dead, but which are inaccessible, because
the program doesn't need them any more.

> >>> > > > The essential thing in being able to detect the problem, of
> >>> > > > course, is not allowing memory to be reused as long as there is
> >>> > > > still an existing pointer to it. Garbage collection, in sum.
> >>> > > > (The Boehm collector is often used in this way, as a leak
> >>> > > > detector, and, with additional instrumentation in user code, to
> >>> > > > detect dangling pointers.)

> >> > > No, there are things you can't detect. If you have an array of
ints
> >> > > that can legitimately take all integer values, how can you tell
that
> >> > > you're pointing at an array that will no longer be updated?

> > > But that's the same situation as in C++, or in every other
> > > language. You expect values to be updated every second, say.
> > > For some reason (program error, etc.), the update doesn't occur.
> > > No language feature that I know will protect against that sort
> > > of thing, and no external tool will detect it.

> Maybe I was a bit unclear here. The point I was trying to make is that
> if the updater is no longer writing to it then in C++ it would delete
> the array, but in Java it would leave it lying around. In C++ this may
> be caught. In Java it can't be caught.

Now you're being ridiculous. If the updater is no longer
writing to the object, then the updater is no longer writing to
it. Whether it has been deleted (in C++) is fully orthogonal to
the question, and I've had to deal with cases where the updater
was still writing the data, although the array has been deleted.

> >> > > {*Actually I think making NULL equivalent to zero was a mistake.
It
> >> > > should be a system-defined value.}

> > > NULL is just a macro. A null pointer does contain a
> > > system-defined value. It's not required to be zero, and there
> > > have been systems where it wasn't zero.

> > > What is required is that an integral constant expression which
> > > evaluates to 0 will convert implicitly to whatever the null
> > > pointer value is. A rather peculiar rule, to put it mildly,
> > > since the rules for converting an int to a pointer depend on
> > > whether the int is a constant or not, and if it is a constant,
> > > the value of that constant.

> I'm well aware of this (though I've never actually worked on a system
> where the value used wasn't zero). Maybe I should have written it as
> "null". One of my pet hates is people writing:

> if ( p )
> rather than
> if( p != NULL )

> with a system-defined vaule they couldn't (portably) do this.

Sure you can. The definition of how a pointer is converted to a
bool is that the results are true if the pointer is non null.
(That doesn't mean that I approve of "if (p)". Say what you
mean, and mean what you say, IMHO. if requires a logical
boolean, and it is very poor programming practice to give it
anything else.)

> But, as you say, it's just a weird rule anyway.

It's an aspect of C++ that I don't like. Far too many implicit
conversions for my taste. But there's not much we can do about
it without breaking too much code. (IIRC, the authors of the
bool proposal originally proposed deprecating the implicit
conversions of pointers, and I think of numeric types as well,
to bool. They withdrew this part of the proposal in face of the
resistence it encountered.)

--
James Kanze (GABI Software) email:james.kanze(a)gmail.com
Conseils en informatique orientie objet/
Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: PeteK on

James Kanze wrote:
> PeteK wrote:
>
> My experience is that almost no classes have a logical owner.
> Most classes which have a deterministic lifetime manage that
> lifetime themselves. When I'm using garbage collection in C++,
> I'd guess that about 90% of the deletes are "delete this".
>
Which is where our experience differs. For me, most classes are either
on the stack, in a collection or embedded in another class. Only a
small number of classes require the use of smart pointers and in the
end even these are bound to the lifetime of a single class created to
run the application. The word "delete" usually only turns up in
comments.

[...]
>
> > I know that you and Andrei appear to have lots of pointer cycles in
> > your code,
>
> What makes you think that?

I'm basing it in comment you've both made in previous posts/threads,
hence the word "appear".

[...]
> "abc" is "abc", regardless of scope or context. You're letting
> implementation constraints of C++ color your conception.
>
Now you're losing me. Ultimately all objects are just an ordered
collection of chars, so you're basically saying that "everything is
always alive, regardless of scope or context".

> > In C++ we can extend that logical lifetime by using
> > smart pointers and the like, but there is still a defined point when
> > the object is logically dead.
>
> Yes. When no other object can possibly access it.

No!

int * f()
{
int
x = 3;
return &x;
}

x logically dies at the end of the function, but you can still access
it (if you're talking about the memory location it occupies, and in the
context of zombies I can't see what other definition you can use).

In C++ something is logically dead when it's destructor is called. The
fact that you've got live pointers to it doesn't mean it's alive, it
means you've probably got an error in your program.

[...]
> True, but in practice, you don't have to worry about objects
> which aren't logically dead, but which are inaccessible, because
> the program doesn't need them any more.
>
Unless these objects contain precious resources.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: PeteK on

James Kanze wrote:
> PeteK wrote:
>
> > if ( p )
> > rather than
> > if( p != NULL )
>
> > with a system-defined vaule they couldn't (portably) do this.
>
> Sure you can. The definition of how a pointer is converted to a
> bool is that the results are true if the pointer is non null.
> (That doesn't mean that I approve of "if (p)". Say what you
> mean, and mean what you say, IMHO. if requires a logical
> boolean, and it is very poor programming practice to give it
> anything else.)
>
As I said in another reply, this is an artifact of numerics decaying to
bools (which I also dislike, but which was necessary when there was no
boolean type) and the null pointer being equivalent to zero. If the
latter hadn't been true then I very much doubt that a null pointer
would ever have been treated as false.

> > But, as you say, it's just a weird rule anyway.
>
> It's an aspect of C++ that I don't like. Far too many implicit
> conversions for my taste. But there's not much we can do about
> it without breaking too much code. (IIRC, the authors of the
> bool proposal originally proposed deprecating the implicit
> conversions of pointers, and I think of numeric types as well,
> to bool. They withdrew this part of the proposal in face of the
> resistence it encountered.)
>
Understandable, given the amount of code already written. However I
wish that bool had been in from the start, in which case there would
have been a perfect opportunity to remove the implicit conversion.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: peter koch larsen on

Francis Glassborow skrev:
> In article <1165692627.577203.236790(a)80g2000cwy.googlegroups.com>, PeteK
> <pete_k_1955(a)yahoo.co.uk> writes
> >I'm well aware of this (though I've never actually worked on a system
> >where the value used wasn't zero). Maybe I should have written it as
> >"null". One of my pet hates is people writing:
> >
> >if ( p )
> >rather than
> >if( p != NULL )
> >
> >with a system-defined vaule they couldn't (portably) do this. But, as
> >you say, it's just a weird rule anyway.
> 1) I find no difficulty with the idiom if( p ); but that is because I
> have become accustomed to it. And I rather dislike if( p != NULL) as
> that is a negative statement which requires more brain power to process
> (that, I am told, is a general rule, negative statements are harder for
> humans to process correctly)

When I began programming in C, I really disliked if (p), preferring if
(p != NULL).
When I began programming in C++, I preferred if (p != 0) - avoiding
using that hideous NULL macro.
Some more schooling however led me to accept if (p) for pointers,
perhaps because it is so widespread and also because the idion is used
in other places (e.g. for streams).
That said, I really do understand PeteK's point of view: accepting
these "silent" conversions does not always express our intension, and I
do find it an abomination to use it for integral types: if (i) is
simply to confusing: yoou need to check if i is an integral or a
pointer. So there I always prefer if (i != 0). Worse is the negations:
I "never" write
i (!t) when t is not bool.


/Peter


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Mirek Fidler on

> Which is where our experience differs. For me, most classes are either
> on the stack, in a collection or embedded in another class. Only a
> small number of classes require the use of smart pointers and in the

IME, no objects require the use of smart pointers (nor GC). Both GC
and/or smart_ptrs are bad idea. You can always find the scope where the
object instance logically belongs.

Mirek


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]