
On 10/12/2004 09:52 AM, Oleg Fedtchenko wrote: [snip]
Oleg Fedtchenko wrote:
class DocActiveX { protected: Tree* m_pTree;
public: ~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 { private:
shared_ptr<Tree> m_pTree;
public:
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 managed_ptr.
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 follows:
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(ptrOwner.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 ); }