Safe Pointers

Started by
36 comments, last by MtSMox 21 years, 7 months ago
quote:Original post by Anonymous Poster
You want an example of a situation where reference smart pointers leak memory? Every time a method or function internally stores a ref counted smart pointer in a list, like for event dispatching through functors themselves holding such a ptr to the original object, its lifetime might be prolonged because it will live until the last one of the smart ptrs goes out of scope, not the "relevant" one.

This is turning into a *very silly* discussion, so I''ll just answer this point. What you have described above is not an example of a counted pointer leaking memory - it is an example of possibly inappropriate design (we''re in the realm of the hypothetical here). If you do not want a pointer to take shared ownership of an object, thus influencing that object''s lifetime, then you should probably use a weak reference to the object, which allows you to ask "is this object still alive" before accessing the pointee. Nobody''s claiming that smart pointers mean you don''t have to worry about your design.
Advertisement
Hm.


[edited by - DrPizza on August 22, 2002 2:35:11 PM]
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
quote:Original post by SabreMan
This is a cause of much debate in Java circles

O_O.

I thought the matter was entirely settled, as there''s no other way to explain how it''s strictly pass-by-value but also permits functions to mutate objects passed to them.

quote:- whether Java has pointers or not. Personally, I agree with you, only Java folk like to call them "references".

I assume it''s to distance themselves from C and C++ where people write memory leaks.

quote:Lisp programmers also deal with pointers all the time.

Not in any lisp I''ve ever seen.

quote:I don''t know of any languages other than C++ where pointers and references are conceptually different.

I believe that Ada, for instance, has such a distinction between access types (pointers) and references.

quote:Java pretends that it doesn''t have pointers, but *references*. Confusingly, Java''s references are pretty much the same thing as C++''s pointers. References in Java can both be reseated, and can be NULL. Just to add to the mess, Java has the NullPointerException, which is probably a result of Java implementations having been developed by C programmers. Basically, Java''s references *are* pointers.

Indeed. Which is why I say it has pointers.


quote:I can''t think of a single other language that has anything semantically equivalent to C++''s references.

That they''re creatable all by themselves (rather than implicitly as function parameters) seems unusual, but that they should exist at all does not.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
quote:Original post by SabreMan
I thought the matter was entirely settled, as there''s no other way to explain how it''s strictly pass-by-value but also permits functions to mutate objects passed to them.

The debate is between pointer and reference, not pointer and value. It''s a stupid debate.
quote:
Not in any lisp I''ve ever seen.

Pointer access happens under the hood, which seems to be what Java aspires to. If you write:

  (setf a (list 1 2 3))(setf b a)  

Then a b are pointers to the same list. Every value in Lisp is conceptually a pointer (but might not actually be in the case of some primitive types). Since lists are immutable, you don''t suffer any "nasty surprises". That''s the bit which Java programmers miss (and is a useful lesson for C++ programmers to learn).
quote:
I believe that Ada, for instance, has such a distinction between access types (pointers) and references.

I don''t know Ada. Does an Ada reference have the same semantics as a C++ reference?
quote:
Indeed. Which is why I say it has pointers.

I actually don''t know why we''re having this debate, since the post I made which prompted it tacitly acknowledged that Java has pointers, and that nobody seems to complain that Java pointers are "hidden from view".
quote:
That they''re creatable all by themselves (rather than implicitly as function parameters)

Languages which have pass-by-reference, which is what you are talking about, use pointers to implement that. C++ is the only language I''ve used where pass-by-reference means something different to "pass-by-pointer". In languages where there is no distinction between pointer and reference, this does not cause confusion. Heck, even Cobol programmers understand this (some of ''em).


  void f(const MouseEvent&);(...)FrameWindow w(hinst);w.onClick().add(f);vector<object> v;v.push_back(w);  


such an approach does not try to elide pointers from everything and everywhere, but it allows you to do simple things simply and without having to think a lot about them.

What you called "bad design" might just too easily happen to a user of a GUI library who thinks of notifying child windows of important changes by adding those of them who care to and are able to receive such notifications to a list seperate from the main list of child windows.
So either there''s a predefined list class that implicitly doesn''t prolong lifetime of referenced objects, or the programmer has to set up the necessary mechanics himself or to think about removing children from any existing notification lists manually when they are removed during runtime.

Only for the more common case that child windows reference a parent for notification does it make no difference whether the reference is weak. And this only applies for java-like garbage collection, either.

In the case of reference counted pointers, this case is even more dangerous because it implies a circular reference. So how could this problem be solved with reasonable effort unless there are mechanics in place that encourage the use of weak smart pointers by offering a predefined collection class for this purpose with a simple interface, providing add(), remove() and notify() to notify all available elements, no-throw guaranteed?

Users else tend to simply use lists of smart pointers for the purpose, if only because these pretend to be "smart". This is exactly why I don''t really like them as part of a library''s interface. To the unexperienced programmer, they says: "Here, I''m giving you access to a pointer, but don''t be afraid, it''s SMART and will take care of itself." No, it won''t. No, it isn''t. And it should be used with exactly the same care as any pointer type.

Java-Reference-Type like behaviour and predefined collection classes that really "reference" their content in the original sense, without secretly owning and keeping it alive, make it possible to program certain, widely used things like windows and events by just "telling the computer what to do", without really having to think about the inner mechanics.

Java does not reach this noble goal. C++ can, if the library''s author is willing to, because of the possible direct access to the exact semantics. Java seems to do everything by itself, though it cannot. In C++, we have the rare opportunity to create a library with the exact semantics that we want. By enabling the user of our library to work completely without pointers, as long as it regards our library''s interfac, we bring objects back to what they originally were: data types. Just like the ints.

I think this is really one of the things the java developers had in mind when they proposed to make everything a little bit simpler. They went and sacrificed a lot of control over semantics on the shrine of simplification.
The polymorphic Bridge Pattern is the exact opposite approach: The chance for complete control over semantics is taken to reach maximal simplicity for the user, who wants a window variable to represent a window, not a pointer representing a data structure representing a system resource that provides access to a "window".

C++ is good because we are able to realize all kinds of data structures and semantics, not because it would force us to take complete control over everything, whatever we might be doing.

And C++ is good because it allows a combination of Java''s ease of programming, a lot of more possible safety and DETERMINISTIC FINALIZATION.

C++ is good, I like it.

shadi
quote:Original post by SabreMan
The debate is between pointer and reference, not pointer and value. It''s a stupid debate.

I didn''t say that there was a debate between pointer and value. I said that, given the semantics of passing objects to functions, it had no choice but to use pointers.

quote:I don''t know Ada. Does an Ada reference have the same semantics as a C++ reference?

I haven''t actually used Ada, but from what I have read, a parameter that was passed by reference acts as a synonym for the pass in variable, as C++ pass by reference. I have programmed in Pascal, and it''s certainly the case there. Variables passed with "var" are passed by reference, and become synoynms for the passed-in name.

quote:Languages which have pass-by-reference, which is what you are talking about, use pointers to implement that.

C++ uses pointers to implement pass by reference too. I''m sure the standard leaves the implementation theoretically open ended, but that''s how it''s done in practice; so, as far as I can tell, does Ada''s spec.

quote:C++ is the only language I''ve used where pass-by-reference means something different to "pass-by-pointer".

In Ada, for instance, one would have to explicitly declare a function as taking an access type, and one could make that access type point at something else without affecting the original variable. One can''t do such a thing with a value passed by reference.

Likewise, Pascal treats pointers and references differently; the pointers can change what they point at, references can''t; a function that took reference arguments is declared and will work differently from a function that takes pointer by value arguments.

char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
quote:Original post by DrPizza
In Ada, for instance [...]

This is how a pointer to a list is "declared" in a small selection of languages:


    ' Lisp(setf x (list 1 2 3))# Pythonx = [1, 2, 3]// JavaList x;// C++std::list<int> *x;  


Now, in C++, if I want to declare a *reference* to a list, I would say:


  std::list<int> &x = other;    


I don't know how to do that in any other language which I have used. How do you do declare a reference in Ada and Pascal?

[edited by - SabreMan on August 23, 2002 7:24:03 AM]
quote:How do you do declare a reference in Ada and Pascal?

You don''t; at least, not explicitly.

The references get created implicitly when passing parameters to methods.

char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/

This topic is closed to new replies.

Advertisement