| re: Smart Pointer Question
Vijai Kalyan wrote:[color=blue]
> I have been thinking about this and it may have already been thrashed
> out and hung out to dry as a topic of no more interest but here goes.
>
> I found when implementing a smart pointer that the typical
> implementation goes like:
>
> template<typename T>
> class SmartPointer
> {
> // other stuff
>
> T* operator->() const;
> };
>
> Now, when we pass around such a pointer in the following form:
>
> void foo(const SmartPointer<X>& ptr)
> {
> ptr->Function1();
> }
>
> Function1() can be a function that can change the state of the
> underlying object. Being a reference ptr of course cannot be
> reassigned. Consequently, since we are looking at a "pointer" albeit a
> smart one, we may want to actually implement the smart pointer as
> follows:
>
> template<class T,
> class TMutableInterface = T
> class TImmutableInterface = T>
> class SmartPointer
> {
> // other stuff
>
> TMutableInterface* operator->();
> TImmutableInterface* operator->() const;
> }
>
> This has the following effect:
>
> For "const SmartPointer<X, XMI, XImI>& ptr"
>
> ptr->Function1() will only be allowed if Function1() is specified by
> the "ImmutableInterface of X" that is "XImI".
>
> and for "SmartPointer<X, XMI, XImI>& ptr"
>
> ptr->Function2() will only be allowed if Function2() is specified by
> the "MutableInterface of X" that is "XMI".
>
> Thus in effect:
>
> const SmartPointer<T, TMI, TImI>& ptr <=> T const* const ptr
>
> and
>
> SmartPointer<T, TMI, TImI>& ptr <=> T const* ptr
>
> -------
>
> I wonder if this has ever been explored? If so, can someone tell me how
> they used it? I have been writing some utilities as part of my work,
> where I find it useful to return a "const SmartPointer&" and
> "SmartPointer&" depending on what access I want the caller to have.
>
> Comments?[/color]
The trick here is that you are transferring the constness of the
pointer to the pointee, which is a feature some have objected to
because it doesn't match the behavior of raw pointers (TR1/Boost's
smart pointers, for instance, are as close to raw pointers as possible
and don't support transferring the constness). However, that behavior
does match std::vector, which, as a "smart array" of sorts, diverges
from the behavior of raw arrays at the point of constness.
You'll need to watch out for copying to get rid of const, but your
policy-based pointer may take care of that automatically depending on
its copy constructors and assignment operators. In particular,
consider:
struct A { void Mutate(); }
void Foo( const SmartPointer<A,A,const A>& ptr )
{
ptr->Mutate(); // Error!
SmartPointer<A>& backDoor( ptr ); // Error?
backDoor->Mutate(); // No error here
}
Does SmartPointer<A> accept SmartPointer<A,A,const A> for copying?
If you disable copy constructors and assignment operators altogether by
making them private, undefined functions, then SmartPointer can't be
used in standard containers, which is a major drawback (one that
TR1/Boost's smart pointers avoids).
I have used this same technique for smart pointers that are members of
a class, so that if the class is const, the pointees become const also.
This behavior is not *always* desirable, but I find that it is
*usually* what I want and, as with std::vector, the compiler can more
closely watch my const-correctness and catch errors.
M |