Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2002-09-18 07:52:59


From: "David Abrahams" <dave_at_[hidden]>
> > shared_from_raw was one of the options. But it implies that
raw-to-shared
> > conversions are universally needed, something that I don't agree with. I
> > have encountered the "shared_ptr from this" problem several times, and I
> was
> > forced to switch to a custom intrusive-counted pointer because of it;
the
> > problem has also been reported by James Kanze as a major reason to avoid
> > boost::shared_ptr. I don't want to acknowledge the general case - "how
do
> I
> > get a shared_ptr from an arbitrary raw pointer" - as a problem.
>
> It's no less-legitimate than "how do I get a shared pointer from an
> *arbitrary* this pointer".

Good question that demands an elaborate answer.

Consider an interface-based design of the form (assume garbage collection
for now):

struct IX
{
    virtual void f() = 0;
};

IX * createX();

There are two ways to express this in a GC-less world:

1. Intrusive:

struct IX: public virtual counted_base
{

    virtual void f() = 0;
};

intrusive_ptr<IX> createX();

(note that IX must expose its counted_base in order for intrusive_ptr to
work)

2. Non-intrusive:

struct IX
{

    virtual void f() = 0;

protected:

    ~IX() {}
};

shared_ptr<IX> createX();

(note that implementation details are truly hidden.)

I consider (2) a much better design.

Now to the motivating example. Add another interface

struct IY
{
    virtual IX * getIX() = 0;
};

and consider a class that implements both IX and IY:

class Impl: public IX, public IY
{
public:

    virtual void f() // IX::f
    {
    }

    virtual IX * getIX() // IY::getIX
    {
        return this;
    }
};

Translated to shared_ptr terms:

struct IY
{
    virtual shared_ptr<IX> getIX() = 0;

protected:

    ~IY() {}
};

class Impl: public IX, public IY, public counted_base
{
public:

    virtual void f() // IX::f
    {
    }

    virtual shared_ptr<IX> getIX() // IY::getIX
    {
        return shared_from_this(this);
    }
};

Note that the required counted_base derivation (to support shared_from_this)
is visible only to the translation unit that contains Impl, a translation
unit that is typically not visible to the client at all.

Therefore, with this design, shared_from_this is only callable from Impl
member functions or other implementation details.

Had it been called shared_from_raw, this would imply that a raw to shared
conversion is of general utility to the client, and because of the visible
counted_base requirement, this would steer users towards design #1,
something that I don't want to do.

This is also one of the reasons that I don't want to attempt any shared_ptr
"optimizations" that depend on the template parameter being-a counted_base.


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