Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!elroy.jpl.nasa.gov!decwrl!infopiz!lupine!rfg From: rfg@NCD.COM (Ron Guilmette) Newsgroups: comp.lang.c++ Subject: Re: Smart Pointers - Another Proposal Message-ID: <3813@lupine.NCD.COM> Date: 9 Feb 91 20:42:38 GMT References: <1991Feb5.021414.22979@cpsc.ucalgary.ca> <3783@lupine.NCD.COM> <1991Feb8.212951.6212@cpsc.ucalgary.ca> Organization: Network Computing Devices, Inc., Mt. View, CA Lines: 142 In article <1991Feb8.212951.6212@cpsc.ucalgary.ca> gintera@fsd.cpsc.ucalgary.ca (Andrew Ginter) writes: +In article <3783@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes: +> If my proposal for allowing *complete* overloading of `T::operator T&' +> and `T::operator&' were to be accepted, you *would not* need any additional +> help from the compiler. You would however be required to write your code +> carefully (and well) within those few regions of your program where the +> dumb pointers were indeed allowed to roam freely. + +I see now. In your proposal, most designers of an "access controlled" +class X would not implement a public "operator ->" for the smart +pointer class referring to objects of type X. 100% Correct. +Such an operator would +represent an undesirable "leak" of dumb pointers and references to X +into areas of an application which X's designer can't anticipate. 100% Correct. +This means that most "generally useful" operations on X would be +phrased as static member functions or as "friend" functions. Not necessarily. Each "generally useful" member function for a type X object could have a parallel counterpart member function for the "smart pointer" class. When you called the parallel operation for the smart pointer class, the implication would be to perform the given operation on the pointed-at object. +This is +because most users of the class will not be able to use a smart +pointer x to X to say "x -> foo ()". 100% Correct. Since there will be no operator-> or (unary) operator* for the smart pointer class, if `sptr' is one of these smart pointer variables, then both `sptr->foobar()' and `(*sptr).foobar()' will be illegal simply because there are no such operators defined for the `sptr' object. As a matter of fact, this is an important component of my proposed scheme for encapsulating any and all *legitimate non-null* dumb pointer *values* within the class itself and within its (friendly) associated smart pointer class. YOU MUST NOT DEFINE EITHER AN operator* OR AN operator-> FOR THE SMART POINTER CLASS. In current examples of C++ code using "smart pointers" (such as those in some of Stroustrup's papers on the subject) each smart pointer class does define an operator* and an operator-> and these operators typically return values of type `T&' (where `T' is the controlled class). That however would constitute a serious leakage of `dumb' reference values under my proposed scheme. Under my scheme, you would want to AVOID defining any public member functions which yield dumb pointer values or dumb reference values. Assuming that each smart pointer class is ultimately implemented in terms of an actual `dumb pointer' member variable (of the smart pointer class) and assuming that you could (through language rules and careful programming) make sure that valid non-null values of type `dumb pointer to T' could only be generated and/or stored with the class T itself and within its (friendly) associated `smart pointer' class, then you would want to maintain the isolation of all such dumb pointer values within these two classes by writing all member functions of these two classes such that they do not return any of the legitimate non-null dumb pointer values which they may have to the outside world. Rather, whenever some operation (any operation) on such an "encapsulated" dumb pointer value was needed, it would have to be provided as a member function of the smart pointer class in order to fully maintain the encapsulation of the `dumb' values. What I had in mind was something like this: class smart_pointer; class controlled { // ... data members ... operator controlled& (); // make it private! controlled* address_of () // sneeky (and private) way... { return this; } // ...to get address of self friend class smart_pointer; // very important! public: controlled (); ~controlled (); smart_pointer& operator& (); // address-of operator void print_self (); void mutate_self (); void operate_on_self (); }; class smart_pointer { controlled *ptr; // ... other data members ... friend class controlled; // very important! public: smart_pointer (controlled *) { ptr = arg; } smart_pointer (const smart_pointer&); // copy constructor ~smart_pointer (); void print_referent (); void mutate_referent (); void operate_on_referent (); }; // create/generate a smart pointer to one's self smart_pointer& controlled::operator& () { return *(new smart_pointer(this)); } void smart_pointer::print_referent () { ptr->print_self (); } Note that operations upon the dumb pointer member variable `ptr' are kept strictly within the encapsulation region. You could only be confident of achieving the kind of "encapsulation of dumbness" that I have been talking about if: (a) you code carefully, so that no member functions (except private ones) return (or otherwise yield) any dumb pointer or dumb reference values for the controlled class, and (b) the language rules change so that `operator&' applies in cases where you (implicitly) get the address of the zeroth element of an array, and (c) the language rules change so that you can define your own `T::operator T&' (which will actually be used when values of type T are converted to values of type T&) so that you can take control over the production of dumb references, and (d) you define your controlled classes with explicit `T::operator T&' and `T::operator&' operators (making `T::operator T&' private of course). -- // Ron Guilmette - C++ Entomologist // Internet: rfg@ncd.com uucp: ...uunet!lupine!rfg // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.