引用計數
 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 以防萬一