Re: an intrusive smart pointer
A simple way to support this would be to initialize the refcount to zero
in T::T. However, when I attempted to do this, I found the following
issue. If you write:
T::T ()
{
DoSomething (this);}
void
DoSomething (Ptr<T> p)
{}
The call to DoSomething is going to increment and decrement the refcount
to one and back to zero, hence, triggering a delete before the object is
fully constructed.
So, I really wonder if it is possible to support both the direct new
syntax and calls to DoSomething from within the constructor.
regards,
Mathieu
The trouble is that shared_ptr (intrusive or otherwise) really wants
to hold an instance of A, and until A's constructor completes, that
instance does not exist. So inside a ctor, there is no instance of A
to grab onto an put into a shared_ptr.
To illustrate the trouble, lets use enable_shared_from_this (which
semanically is equivalent to intrusive_ptr, in that it allows
reflexive references):
struct A:enable_shared_from_this<A>{
A(){
DoSomething(shared_from_this());//oops, will delete before ctor
exits
}
static DoSomething(shared_ptr<A>);
};
which is the same problem. Placing it in a member doesnt work--
struct A:enable_shared_from_this<A>{
A(){
m_member=shared_from_this(); //hmm now A will never get reclaimed
DoSomething(m_member);
}
static DoSomething(shared_ptr<A> );
shared_ptr<A> m_member;
};
OK we can try to fix that problem using a static
struct A:enable_shared_from_this<A>{
A(){
m_member=shared_from_this(); //at least previous A is reclaimed
DoSomething(m_member);
}
static DoSomething(shared_ptr<A> );
static shared_ptr<A> m_member;
};
Now we have problems with the MT case. Plus, we also have this issue
struct A:enable_shared_from_this<A>{
A(){
m_member=shared_from_this();
DoSomething(m_member);//throws exception
}
static DoSomething(shared_ptr<A> ){throw 1;}
static shared_ptr<A> m_member;
};
Now, m_member is hanging on to invalid memory, since the exception
handling mechanism already deleted A, leaving a dangling pointer
inside of m_member, which is exactly what you are trying to avoid.
Hmmm how about this?
struct no_op{
void operator()(void*){}
};
struct A:enable_shared_from_this<A>{
A(){
shared_ptr<A> m(this,no_op());
DoSomething(m);
}
static DoSomething(shared_ptr<A> );
};
This is not a perfect solution, esp if DoSomething really needs to
hold a live A (for instance, it inserts an shared_ptr<A> into a vector
of live A instances). So that is not a general solution either.
So there are solutions depending on the behavior of DoSomething, but
nothing that works in general. In fact, the shared_ptr standard
requires that the ctor argument be a pointer to the complete type, and
I suppose that should also read the complete instance to a complete
type, i.e. not before it was fully constructed.
Lance
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]