1. 生命期控制
当使用完一个接口而仍要使用另外一个接口时,是不能将此组件释放掉的。很难知道两个指针是否指向同一个对象。IUnknown的另外两个函数AddRef和Release来指示合适处理完一个接口的手段。
2. 引用计数简介
AddRef和Release实现的时一种名为引用计数的内存管理技术。引用计数是使组件能够自己将自己删除的最简单同时也是效率最高的方法。当客户从组件取得一个接口时,此引用计数就增加1,使用完某个接口后组件将引用计数减1,当引用计数为0的时候组件将自己从内存中删除。
- 在返回之前调用AddRef。对于那些返回接口指针的函数,在返回之前应用相应的指针调用AddRef,这样当客户从函数获得一个接口后就无需调用AddRef
- 使用完接口之后调用Release。在使用完某个接口之后应调用此接口的Release函数。
- 在赋值之后调用AddRef。在讲一个接口指针赋值给另外一个接口指针时,应调用AddRef。
引用计数接口
从客户来看:每一个接口都有一个引用计数。从组件来看:组件可以维护一个引用计数。
为每个接口都有一个引用计数而不是针对组件维护,原因:
1、 是程序调试更为方便
2、 支持资源的按需获取
在实现某个接口时可能需要大量的内存或者其他资源,可以在QueryInterface中实现,在客户请求此接口时完成资源的分配。但若只对组件维护一个引用计数那么组件将无法决定何时可以安全将同此接口相关的内存释放。
AddRef和Release的实现
ULONG __stdcallAddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcallRelease()
{
if(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
何时使用引用计数—引用计数规则
- 输出参数规则
输出参数指给函数的调用者传会一个值的函数参数,在函数体中设置此参数的值。任何输出参数或返回值返回一个新的接口指针的函数必须对此接口指针调用AddRef。
- 输入参数规则
输入参数指给函数传递某个值的参数,在函数体中会使用这个值但不会修改它。对传入的接口指针无需调用AddRef和Release,因为函数的生命期嵌套在调用者的生命期中。
- 输入-输出参数规则
输入-输出蚕食同时具有输入参数及市场参数的功能,在函数体中可以使用输入-输出参数的值。在函数中对于输入-输出参数传递进来的接口指针,必须在给他赋另外一个接口指针值之前调用Release。在函数返回之前,还必须对输出参数中所保持的接口指针调用AddRef。
- 局部变量规则
对于局部复制的接口指针,由于只是在函数的生命期内才存在,因此无需调用AddRef和Release
- 全局变量规则
对于保持在全局变量中的接口指针,在讲起传递给另外一个函数之前,必须调用AddRef