From: James Kanze on 11 Dec 2006 09:02 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 11 Dec 2006 16:22 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 11 Dec 2006 16:20 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 11 Dec 2006 16:23 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 11 Dec 2006 18:10
> 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! ] |