2009-12-10 194 views
0

我經常遇到這樣的問題,即我有一個具有一對Register/Unregister類型方法的類。例如:在C++中實現寄存器/取消寄存器模式

class Log { 
public: 
    void AddSink(ostream & Sink); 
    void RemoveSink(ostream & Sink); 
}; 

這適用於幾種不同的情況,如觀察者模式或相關的東西。我擔心的是,這有多安全?從previous question我知道,我無法安全地從該引用中派生出對象標識。 This approach返回一個迭代器給調用者,他們必須傳遞給註銷方法,但是這暴露了實現細節(迭代器類型),所以我不喜歡它。我可以返回一個整數句柄,但這需要很多額外的內部管理(什麼是最小的空閒句柄?)。你如何去做這件事?

回答

2

除非客戶端對象有兩個派生的ostream而不使用虛擬繼承,否則您是安全的。

總之,這是用戶的錯誤 - 它們不應該以兩種不同方式兩次繼承接口類。

使用該地址並完成它。在這些情況下,我使用指針參數而不是參考來明確指出我將存儲地址。它還可以防止在您決定採用const引用時可能會觸發的隱式轉換。

class Log { 
    public: 
     void AddSink(ostream* Sink); 
     void RemoveSink(ostream* Sink); 
    }; 

您可以在析構函數創建一個在構造函數調用AddSink一個RAII對象,RemoveSink使這種模式異常安全。

0

您可以使用智能指針來管理您的對象,並比較指針在註冊/取消註冊函數內是否相等。

如果您只有堆棧分配的對象從不在註冊和註銷調用之間複製,您也可以傳遞指針而不是引用。

你也可以這樣做:

typedef iterator handle_t; 

,並隱瞞事實,你給了內部迭代器,如果暴露內部數據結構你擔心。

+0

智能指針用於對象的共享所有權,這裏不是這種情況。另外,我認爲我引用的其他問題中討論的內容也適用於智能指針。 – 2009-12-10 14:11:56

+0

對不起,我的糟糕的智能指針與shared_ptr不同,所以請忽略我的評論部分。 – 2009-12-10 14:12:52

+0

答案也發佈在其他問題中。只要你比較相同類型的指針(比如ISink),一切都很好。 – Sebastian 2009-12-10 14:18:55

0

在你之前的問題中,Konrad Rudolph posted an answer(你沒有接受但是得分最高),如果你使用了基類指針,那麼你應該沒問題,你似乎這樣做。