IUnknown 的另外两个方法:
即AddRef和Release方法.用这两个方法可以有效的管理组件的生命周期。
一.引用计数三大规则
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() ;
生命期嵌套在引用同一接口的指针的生命期内的指针可以不进行引用计数。在函数中,无需对存在于局部变量的接口指针进行引用计数。因为局部变量的生命期同函数的生命期是一样的,因此也将包含在调用者的生命期内。但当从某个全局变量或向某个全局变量复制一个指针时,则需要对此指针进行引用计数,因为全局变量可以从任意函数中的任意地方被释放。
总结引用计数的几条具体规则如下:
(1) 输出参数规则。任何在输出参数中(如QueryInterface的void** ppv)或作为返回值返回一个新的接口指针的函数必须对此接口指针调用AddRef。即在返回之前调用AddRef。
(2) 输出参数规则。在输入参数(C++的按值传递的参数或常量)传入函数的接口指针,无需调用AddRef和Release。因为函数的生命期嵌套在调用者的生命期内。
(3) 输入-输出参数规则,即在函数体中可以使用输入-输出参数的值,然后可以对这些制进行修改并将其返回给调用者,对于具有这种功能的参数传进来的接口指针,必须在给它赋另外一个接口指针值之前调用其Release,并在函数返回之前,对输入参数中所保存的接口指针调用AddRef。
(4) 局部变量规则。对于局部复制的接口指针,由于它们只在函数的生命期内才存在,无需调用AddRef和Release。
(5) 全局变量规则。对于保存在全局变量中的接口指针,在将其传递给另外一个函数之前,必须调用其AddRef。对于保存在成员变量中的接口指针,也应按此中方式进行处理。因为类中的任何成员函数都可以改变此中接口指针的状态。
(6) 不能确定时的规则。对于任何不能确定的情形,都应调用AddRef和Release。