如果你在析构函数中做了很多的事,你将会有一些麻烦。
举个例子,假如你在析构函数中调用了一些其它函数,而这些函数内部操作中可能又会调用到IUnknown::AddRef 和 IUnknown::Release方法。考虑下面这个代码:
ULONG MyObject::Release()
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (cRef == 0) {
delete this;
}
return cRef;
}
MyObject::~MyObject()
{
if (m_fNeedSave) Save();
}
看起来这个代码中没有问题。我们在释放函数中执行保存对象功能。
但是,这个保存函数可能如下:
HRESULT MyObject::Save()
{
CComPtr<IStream> spstm;
HRESULT hr = GetSaveStream(&spstm);
if (SUCCEEDED(hr)) {
CComQIPtr<IObjectWithSite, &IID_IObjectWithSite> spows(spstm);
if (spows) spows->SetSite(this);
hr = SaveToStream(spstm);
if (spows) spows->SetSite(NULL);
}
return hr;
}
这看起来也没有什么问题。取得一个IStream并且执行保存,其中把this作为SetSite的参数。
事实上这会带来一些问题,请看下面的分析:
因此,至少,你应该在你的AddRef()函数中增加一个assert,以保证你的引用计数不能从0上增加。
ULONG MyObject::AddRef()
{
assert(m_cRef != 0);
return InterlockedIncrement(&m_cRef);
}