|
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