Boost logo

Boost :

From: Larry Evans (cppljevans_at_[hidden])
Date: 2004-10-12 12:59:29

On 10/12/2004 09:52 AM, Oleg Fedtchenko wrote:
>>>Oleg Fedtchenko wrote:
>>>class DocActiveX
>>> Tree* m_pTree;
>>> ~DocActiveX(){ if(m_pTree) delete m_pTree;}
>>> bool Load( const char* lpszPath);
>>> Tree* Parse(){ return m_pTree;}
>>Peter Dimov wrote:
>>That's the easy part.
>>class DocActiveX
>> shared_ptr<Tree> m_pTree;
>> bool Load( const char* lpszPath );
>> shared_ptr<Tree> Parse() { return m_pTree; }

> Ok. But if m_pTree has a pointer to its owner (of type
> DocActiveX) then it's possible that m_pTree will access through
> that pointer after its owner is deleted. Using shared_ptr to
> its owner will cause a deadlock (a member cannot have a
> shared_ptr to its owner).

A solution to this problem of cyclic references is in the sandbox under

> Another task is:
> class DocActiveX
> {
> private:
> Tree m_Tree; // it's an object, not a pointer
> public:
> bool Load( const char* lpszPath );
> Tree* Parse() { return &m_Tree; }
> };

> To allow creating a safe shared_ptr pointing to a class member there
> is need in such a code:
The following is clearer to me:

   To allow creating a safe shared_ptr pointing to a class member there
   is the need for a new shared_ptr contructor that can be used as

> shared_ptr<Tree> Parse( shared_ptr<DocActiveX> ptrOwner)
> {
> shared_ptr<Tree> ptrMember( &m_Tree, ptrOwner);
> return ptrMember;
> }

> And corresponding ctor that passes over a deletable pointer to an
> owner (ptrOwner) of a class member (p):

> template <class Y, class Z>
> shared_ptr( Y * p, shared_ptr<Z>& ptrOwner)
> : px(p), pn(
> {...}

> It's good as it allows to use shared_ptr.

I think this amounts to enabling "interior" pointers to be used
as arguments to shared_ptr CTOR. An "interior" pointer is a
pointer to the interior, not the beginning, to an object. I
believe the original reason for share_ptr<Z>::px was to allow its
use for multiply inherited objects and allow conversion to the
2nd superclass:

   class A{int a;};class B{float b;};
   class AB: public A,B{};

   shared_ptr<AB> pAB(new AB);
   shared_ptr<B> pB(pAB);

However, now that you've mentioned it, I don't see any reason why
it couldn't be used as proposed for a shared_ptr to B::b:

   share_ptr<float> pBb(&pB->b,pB);

> But it's good if this class will never be used as an object
> (nondynamic) data-member inside another owner.

This is unclear to me. Could you provide an example?

> Also it's good when we create shared_ptr using ptrOwner outside
> a class because we can pass in a shared_ptr of any owner.

Could you also provide an example for this?

> But when we use shared_ptr inside a class (like in this example) it
> has three drawbacks.

> The body of the function must be aware of the type of an owner. It
> prevents this code from being used in a DLL until the owner type is
> well-known (e.g. declared in boost).

Well, I think all the information needed is in shared_ptr::pn.
After all, it knows the actual type of the owner. That was the
reason for the two pointers, px and pn, in shared_ptr. The 2nd
actually knows the type of the owner. Am I missing something?

> Another thing is that it's impossible to use custom add_ref() and
> release() for an owner the way it is done in intrusive_ptr. I mean
> a developer of a class must choose one of the shared_ptr and
> intrusive_ptr (if the last is extended to support a smart member
> pointers). But we want this class to be used inside owner of any
> type. And one owner will live with just *delete me* but another
> owner will require *let me do some processing and then delete me
> myself*.

Can't *let me do some processing and then delete me
myself* be done with a custom deleter argument to shared_ptr?
I.e. with the CTOR:

     template<class Y, class D> shared_ptr(Y * p, D d): px(p), pn(p, d)
         detail::sp_enable_shared_from_this( pn, p, p );

Boost list run by bdawes at, gregod at, cpdaniel at, john at