com学习笔记(3)基本的com接口-引用计数的实现
2009-07-05 23:12 Clingingboy 阅读(1351) 评论(0) 编辑 收藏 举报clr内存是托管的,但c++不是.我们用完组件还得回收。那么就有一个问题。我们需要知道使用中的组件可以释放了吗?必须想一种机制在适当的时候来释放资源,于是就有了引用计数的概念.IUnknown还有其他两个成员,我们没有讲过
即AddRef和Release方法.用这两个方法可以有效的管理组件的生命周期。
AddRef则计数加1
Release则计数减1,若等于0则释放资源
interface IUnknown { virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) =0; virtual ULONG __stdcall AddRef() =0 ; virtual ULONG __stdcall Release() =0 ; };
一.引用计数三大规则
1.在返回接口指针时调用AddRef.
IUnknown* CreateInstance() { IUnknown* pI = static_cast<IX*>(new CA) ; pI->AddRef() ; return pI ; }
2.在使用完接口时调用Release.用户很懒,总是想让系统自己释放资源,但只有用户自己才知道什么时候不需要使用了.还得用户自己来调
记得接口用完后调用Release
如下代码
int main() { HRESULT hr ; trace("Client: Get an IUnknown pointer.") ; IUnknown* pIUnknown = CreateInstance() ; trace("Client: Get interface IX.") ; IX* pIX = NULL ; hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX) ; if (SUCCEEDED(hr)) { trace("Client: Succeeded getting IX.") ; pIX->Fx() ; // Use interface IX. pIX->Release() ; } trace("Client: Get interface IY.") ; IY* pIY = NULL ; hr = pIUnknown->QueryInterface(IID_IY, (void**)&pIY) ; if (SUCCEEDED(hr)) { trace("Client: Succeeded getting IY.") ; pIY->Fy() ; // Use interface IY. pIY->Release() ; } trace("Client: Ask for an unsupported interface.") ; IZ* pIZ = NULL ; hr = pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ) ; if (SUCCEEDED(hr)) { trace("Client: Succeeded in getting interface IZ.") ; pIZ->Fz() ; pIZ->Release() ; } else { trace("Client: Could not get interface IZ.") ; } trace("Client: Release IUnknown interface.") ; pIUnknown->Release() ; return 0; }
3.在赋值后调用AddRef.
pIX->Fx() ; // Use interface IX.
IX* pIX2=pIX;
pIX2->AddRef();
pIX2->Fx();
pIX2->Release() ;
pIX->Release() ;
二.引用计数接口单一维护
上面我们可以看到,每个引用计数接口都是单一维护,很麻烦.
为何不在同一个组件统一维护呢?解释是为了方便后续调试和资源的释放.等接口多了就很难管理,万一是全局设计,就很难找出是哪个接口的问题了.(我感觉这完全是设计问题,但确实是个问题)
三.引用计数的实现
返回值供调试使用,其他地方意义不大。
ULONG __stdcall CA::AddRef() { cout << "CA: AddRef = " << m_cRef+1 << '.' << endl ; return InterlockedIncrement(&m_cRef) ; } ULONG __stdcall CA::Release() { cout << "CA: Release = " << m_cRef-1 << '.' << endl ; if (InterlockedDecrement(&m_cRef) == 0) { delete this ; return 0 ; } return m_cRef ; }
到此为止,用户的使用从直接用delete关键字变成用Release释放资源.
四.何时进行引用计数
1.若生命周期包含,可以省却引用计数
pIX->Fx() ; // Use interface IX. IX* pIX2=pIX;pIX2->AddRef();pIX2->Fx();pIX2->Release() ;pIX->Release() ;
2.生命周期不包含则无法省却
顺序换一下就大不一样了.
IX* pIX2=pIX; pIX->Fx() ; pIX2->AddRef(); pIX->Release() ; pIX2->Fx(); pIX2->Release() ;
五.引用计数规则
下次继续