Re: Re-entering Release() - strange crash
Igor R. <igor.rubinov@gmail.com> wrote:
class ATL_NO_VTABLE CRoot :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CRoot, &CLSID_Root>,
public IDispatchImpl<IRoot, &IID_IRoot, &LIBID_ATLRefcountLib, 1, 0>
{
public:
CRoot() : creatingInstance_(false)
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_ROOT)
DECLARE_NOT_AGGREGATABLE(CRoot)
BEGIN_COM_MAP(CRoot)
COM_INTERFACE_ENTRY(IRoot)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
init();
return S_OK;
}
ULONG InternalAddRef()
{
if (m_dwRef == 0)
creatingInstance_ = true;
return CComObjectRootEx::InternalAddRef();
}
ULONG InternalRelease()
{
ULONG ref = CComObjectRootEx::InternalRelease();
if (ref == 1 && holder_)
{
if (creatingInstance_)
creatingInstance_ = false;
else
release();
}
return ref;
}
I don't understand the significance of creatingInstance_ flag here. To
my untrained eye, it appears that, because of that flag, your code would
never take the branch where it calls release().
private:
void init()
{
AddRef();
holder_.reset(this, std::tr1::mem_fn(&CRoot::Release));
}
void release()
{
holder_.reset();
}
Since release() is never called, holder_ calls CRoot::Release() when
it's destroyed, which happens in CRoot's destructor. Hence the recursive
call you are observing.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925