Boost logo

Boost :

From: David Abrahams (david.abrahams_at_[hidden])
Date: 2002-01-05 21:10:52


From: "Beman Dawes" <bdawes_at_[hidden]>
> At 03:58 PM 1/4/2002, David Abrahams wrote:
>
> >I have suggested several times that we look at the Policy Adaptor
pattern
> >used by the Iterator Adaptors Library. It certainly makes the problem of
> >policy interaction go away, since all of the policies are collected in
> one
> >place... but there have been no replies, and I am wondering why. Is it
> seen
> >as inappropriate for smart pointers? Are people having trouble
> >understanding the suggestion?
>
> I am. Every time you mentioned it (once in person, several other times in
> postings), I went back and read portions of the paper. In particular, the
> section below. How does it a apply to smart pointers? Smart pointers
> don't seem to have nice neat models of concepts like InputIterator,
> ForwardIterator, BidirectionalIterator, or RandomAccessIterator. Or if
> they did, there would be hundreds of them.

I don't think that really changes things much. The Policy Adaptor pattern
doesn't depend on having strictly-defined concept models any more than the
pattern used by Andrei does, AFAICT.

> I think the iterator example is
> confusing me. With smart pointers the starting point (in my mind) is a
> feature model. That translates nicely (as done by Andrei) into a set of
> policies, which are for the most part orthongonal.

The analogy with iterators is a fairly strong one. You could think of
writing an iterator library with dereference, motion, and comparison
policies, for example.

> Each of the policies
> has two or more default implementations, corresponding to the common
> feature variations for that Policy. I don't understand how to (usefully)
> mash the policies together into a single policy. I'm basically lost.

I think your nested inheritance model effectively does that, since the
SmartPtr is effectively derived from a single class which is a composition
of all of the policies:

template <
typename T,
template <class> class OwnershipPolicy,
template <class> class ConversionPolicy,
template <class> class CheckingPolicy,
template <class> class StoragePolicy >
class SmartPtr
: public ConversionPolicy <
typename OwnershipPolicy <
typename CheckingPolicy <
typename StoragePolicy<T> > > >
{ ...

A small variation might be all that's required to make it easier to build
policy interactions:

template <typename T, typename Policies>
class SmartPtr : public Policies
{
...
};

The Policy Adaptor pattern uses template member functions so that it isn't
neccessary to pass T as a template parameter to each of the policies.
Andrei's policies also supply types; these could be handled with nested type
generators if neccessary:

struct my_policies
{
    ...

    template <class T>
    struct traits
    {
        typedef T* StoredType; // the type of the pointee_ object
        typedef T* PointerType; // type returned by operator->
        typedef T& ReferenceType; // type returned by operator*
    };

    template <class SmartPointer>
    typename SmartPointer::ReferenceType dereference(SmartPointer const& x)
    {
        // implementation of dereference behavior
    }
};

We can supply orthogonal default policy components as follows, if desired:

struct empty {};

template <class MorePolicies = empty>
struct default_smart_ptr_storage : MorePolicies
{
    ...
};

template <class MorePolicies = empty>
struct default_smart_ptr_conversion : MorePolicies
{
    ...
};

So they can be chained together:

struct my_policies :
default_smart_ptr_storage<default_smart_ptr_conversion<> >
{
    // my checking and ownership policy code here

    // this allows as much interaction as desired
    // between the checking and ownership aspects
};

But we can also provide:

struct default_smart_ptr_policies :
    default_smart_ptr_storage<
        default_smart_ptr_conversion<
            default_smart_ptr_checking<
                default_smart_ptr_ownership<> > > >
{
};

The Policy Adaptor pattern would encourage users to derive new policies from
default_smart_ptr_policies, replacing one element of the functionality at a
time. Typically, this approach is useful if a user is going to hand the
libarary one kind of "pointer" and request a variation on that pointer in
return (think of reverse_iterator or indirect_iterator for example).
Although it is not clear to me that this is a common need in the domain of
smart pointers (is it?), the concrete policy class may be useful for solving
the policy interaction problem.

One key difference I notice in Andrei's design is that the policies seem to
supply element's of the SmartPtr's public interface directly (e.g. op->()) .
It isn't clear to me whether this is essential or not; we should discuss it.

-Dave


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk