1、生命期控制
IUnknown的另外两个成员函数AddRef和Release的作用就是给客户提供一种让它指示何时处理完一个接口的手段。
2、AddRef和Release实现的是一种名为引用计数的内存管理技术。
引用计数是使组件能够自己将自己删除的最简单同时也是效率最高的方法。
COM组件将维护一个称做是引用计数的数值。当客户从组件取得一个接口时,此引用计数值将增1。当客户使用完某个接口后,组件的引用计数值将减1。当引用计数值为0时,组件即可将自己从内存中删除。
3、正确使用引用计数规则:
(1)在返回之前调用AddRef。对于那些返回接口指针的函数,在返回之前应用相应的指针调用AddRef。这些函数包括QueryInterface及CreateInstance。这样当客户从这种函数得到一个接口后,它将无需调用AddRef。
(2)在使用完接口之后调用Release。在使用完某个接口之后应调用此接口的Release函数。
(3)在赋值之后调用AddRef。在将一个接口指针赋给另外一个接口指针时,应调用AddRef。换句话说,在建立接口的另外一个引用之后应增加相应组件的引用计数。
4、在客户看来,引用计数是处于接口级上而不是组件级上的。
5、为什么选择为每一个接口单独维护一个引用计数而不是针对整个组件维护引用计数?
(1)使程序调试更为方便;
(2)支持资源的按需获取。
6、AddRef&Release的例子
ULONG _stdcall AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG _stdcall Release()
{
if(InterlockedDecrement(&m_cRef)
{
delete this;
return 0;
}
return m_cRef;
}
7、当建立一个新组件时,应建立一个对此组件的引用。因此创建组件时,在将指针返回给客户之前,应该增大组件的引用计数值。这使程序员可以不必在调用CreateInstance 或QueryInterface之后记着去调用AddRef。
8、引用计数规则优化:
(1)输出参数规则:任何在输出参数中或作诶返回值返回一个新的接口指针的函数必须对此接口指针调用AddRef。
(2)输入参数规则:对传入函数的接口指针,无需调用AddRef和Release,这是因为函数的生命期嵌套在调用者的生命周期内。
(3)输入-输出函数规则:对于用输入-输出参数传递进来的接口指针,必须在给它赋另外一个接口指针之前调用其Release。在函数返回之前,还必须对输出参数中所保存的接口指针调用AddRef。如:
void ExchangeForCachedPtr( int i, IX **ppIX)
{
(*ppIX)->Fx(); //Do something with in-parameter.
(*ppIX)->Release();//Release in parameter.
*ppIX = g_Cache[i];//Get cached pointer.
(*ppIX)->AddRef();//AddRef pointer.
(*ppIX)->Fx();//Do something with out-parameter.
}
(4)局部变量规则:对于局部复制的接口指针,由于它们只是在函数的生命周期内才存在,因此无需调用AddRef和Release。
(5)全局变量规则:对于保存在全局变量中的接口指针,在将其传递给另外一个函数之前,必须调用其AddRef。由于此变量是全局的,因此任何函数都可以通过调用其Release来终止其生命期。对于保存在成员变量中的接口指针,也应按此种方式进行处理。因为类中的任何成员函数都可以改变次中接口指针的状态。
(6)不能确定时的规则:对于任何不能确定的情形,都应调用AddRef和Release对。
9、COM中关于引用计数的一个完整例子源码:CSDN我的资源中InsideCOM\CHAP04。