2010-04-15 62 views
3

最常見的可重用引用計數對象使用私有繼承來實現重用。我不是私有繼承的一個巨大的風扇,和我很好奇,如果這是處理事情能夠接受的方式:可以通過構圖實現引用計數嗎?

class ReferenceCounter { 
    std::size_t * referenceCount; 
public: 
    ReferenceCounter() 
     : referenceCount(NULL) {}; 
    ReferenceCounter(ReferenceCounter& other) 
     : referenceCount(other.referenceCount) { 
      if (!referenceCount) { 
       referenceCount = new std::size_t(1); 
       other.referenceCount = referenceCount; 
      } else { 
       ++(*referenceCount); 
      } 
    }; 
    ReferenceCounter& operator=(const ReferenceCounter& other) { 
      ReferenceCounter temp(other); 
      swap(temp); 
      return *this; 
    }; 
    void swap(ReferenceCounter& other) { 
     std::swap(referenceCount, other.referenceCount); 
    }; 
    ~ReferenceCounter() { 
     if (referenceCount) { 
      if (!*referenceCount) 
       delete referenceCount; 
      else 
       --(*referenceCount); 

     } 
    }; 
    operator bool() const { 
     return referenceCount && (*referenceCount != 0); 
    }; 
}; 

class SomeClientClass { 
    HANDLE someHandleThingy; 
    ReferenceCounter objectsStillActive; 
public: 
    SomeClientClass() { 
     someHandleThingy = RegCreateKeyEx(...); 
    } 
    ~SomeClientClass() { 
     if (objectsStillActive) 
      return; 
     RegCloseKey(someHandleThingy); 
    }; 
}; 

還是有這個,我沒有看到細微的問題?

編輯
我不是超級騙子關心這個特殊的實現(它可能有錯誤 - 我會花一些時間在生產中使用的代碼這樣的事情之前在看的shared_ptr的內臟) - 我只關心,如果一般有一個具體的原因可重複使用的引用計數好吃的東西似乎總是使用繼承而不是組合實現。

回答

3

複製手柄時必須記得複製計數器。您可能不希望將操作系統類型傳遞到模板中,但我認爲這裏的安全性需要繼承。 (不是從HANDLE繼承,但是。)

HANDLE也可能是一種特殊情況,因爲它是POD。除了T*之外,基本上你有一個類型的指針。

我看到你想要除delete以外的其他動作發生在計數變爲零時。 smart_ptr可能適用,你可能不會那麼做。

+0

如果發生這種情況,則會複製A. ReferenceCount對象(因爲referenceCount不是NULL指針),並且B. referenceCount爲零,表示我們正在銷燬組中的最後一個ReferenceCount。所以size_t指針需要被釋放。 – 2010-04-15 01:55:15

+0

@Billy:但是現在你已經擦除了計數器,你不能讀取它來確定是否刪除受控對象。這裏似乎只是參考計數的唯一東西就是櫃檯本身。我想我錯過了一些界面。 – Potatoswatter 2010-04-15 01:58:01

+0

如果最後一個ReferenceCount對象被銷燬,無論如何,沒有人會再次訪問計數器。 – 2010-04-15 01:59:12

0

我不認爲這有什麼價值。引用計數僅適用於共享對象。目標是節省堆分配和/或複製這些內容。實際上,你實施了複製計數器。但即使這樣也沒有用,因爲它沒有提供任何接口來查詢計數器值。我可以建議重溫boost::intrusive

+0

該接口是'operator bool',它返回ReferenceCount對象是否是最後剩下的'ReferenceCount'對象。提升侵入性仍然需要堆分配,我不想複製時不想複製。 – 2010-04-15 02:14:15

0

您實際上正在執行HANDLE類以外的HANDLE的引用計數......該死的接近shared_ptr

使用組合來實現引用計數是很好的,但如果引用計數對象ReferenceCounter要擁有類HANDLE實例會更好......使用更安全,並且由於您只實現刪除例程而更便宜一次而不是在你的所有構造函數中完成(arg)。

使用私有繼承的單一有效理由是Empty Base Optimization,所有其他情況下可以處理的組合在耦合方面好得多,所以他們不太可能有充足的理由這樣做,更可能他們做到了出於誤導或懶惰。

+0

「使用更安全,重用更便宜,因爲您只執行一次刪除例程,而不是在所有構造函數中執行(arg)。」 < - 任何使用它的客戶端都將是HANDLE對象的唯一管理者。這種客戶類的任何構造函數都將是一個簡單的前端,它調用WindowsAPI函數並將句柄存儲在RAII類中。 EBO在這裏沒有用處,因爲引用計數類需要指針的大小來存儲。 – 2010-04-15 12:08:26

相關問題