引用计数
 COM接口采用引用计数来控制组件的生命周期。
 主要用AddRef ,Release 来进行内存管理,当客户从组件中取得一个接口时,此引用计数值将增1。当客户使用完某个接口后,组件的引用计数值将减1。
 当引用计数值为0时,组件即可将自己从内从中删除。
 
 (1)正确使用引用计数的三条简单原则:
   1)在返回之前调用AddRef.
   2)使用完接口后调用Release.
   3)在赋值之后调用AddRef(指针复制).
  基本原则是避免在使用组件时,组件已被删除。
  QueryInterface 和CreateInstance中已经调用了AddRef,因此不必再调用它。
  但两者返回的IUnknow接口和一般接口,用完后都需要调用Release来释放。
  一般而言,每当复制一个接口的指针时,都应该相应的增加引用计数。
   IUnknown* pIUnknown=CreateInstance();
   IX * pIX=NULL;
   HRESULT hr= pIUnknown->QueryInterface(IID_IX,(void **)&pIX);
   pIUnknown->Release();
   if(SUCCEEDED(hr))
   {
    pIX->Fx();    //Fx()为功能函数
    IX * pIX2=pIX;   //复制指针,即增加了一个使用组件(的接口)的可能,
    pIX2->AddRef();  //所以要增加计数,并在使用完之后release
    pIX2->Fx();     
    pIX2->Release(); //
    pIX->Release(); 
   }
   //上面代码中,作为复制指针pIX2,其生存周期与pIX相同,即,在pIX Release之前pIX2就已经不再使用了,
   pIX保证了组件使用安全的前提下,pIX不用AddRef和Release是肯定没问题的。
   
   但有时很难判断某些没有加上AddRef和Release的调用是不是正确,是优化还是程序错误。一般用智能来封装
   引用计数,从而解决这个问题。(智能指针)
   
   组件可以对其每一个接口分别维护一个引用计数,也可以对整个组件维护单个的引用计数。原则上选择了为每一个
   接口单独维护一个引用计数而不是针对整个维护计数,原因,一,使程序调试更方便,二,支持系统资源的按需获取。
   
 (2)AddRef\Release 实现
   主要是改变成员变量m_cRef的数值。AddRef增加其数值,Release减小数值,并在此值为0时将组件删除。
   简单实现:
    ULONG _stdcall AddRef()
    {
     return ++m_cRef;//return InterlockIncrement(&m_cRef);
    }
    ULONG _stdcall Release()
    {
     if(--m_cRef==0)//if(InterlockDecrement(&m_cRef)==0)
     {
      delete this;
      return 0;
     }
     return m_cRef;
    }
   一般用InterlockIncrement和InterlockDecrement来实现AddRef\Release; 可以确保同一时间只有同一线程来访问成员变量。
  3)引用计数的优化原则
    就像(1)中例子,pIX能保障在pIX2生命周期内,组件肯定会在内存内存留。即,那些生命周期嵌套在引用同一接口的指针的生命周期之内时,外层的已有引用计数,内层的就可以不要了。
    注意那些生命周期重叠的指针。
    (1)输出参数原则
      如果接口指针以函数返回值或者以传出参数传出,那么在函数内部,返回参数前调用AddRef.
      例 QueryInterface/CreateInstance;
    (2)输入参数原则
      若接口指针作为参数传递给一个函数,该函数不修改也将其返回调用者,此时无需调用AddRef\Release例:
       void foo(pIX *pIX)
       {
        pIX->Fx();
       }
       因为函数的生命周期嵌套在调用者的生命周期之内的。
    (3)输入输出参数原则
      对于传递进来的接口指针,必须在给他附另外一个接口指针之前调用release;返回之前,还必须对输出参数指向的新接口调用AddRef;
  4)局部变量原则
    它们是在函数的生存周期内才存在,因此不需要调用AddRef\Release
  5)全局变量原则
    在传递给另一个函数之前,必须调用AddRef.
  6)不确定的情况
    此时需要调用AddRef\Release 以防万一