2009-12-06 65 views
1

說我有一個具有Initialize()方法的類型A的對象。 該方法接收對象B,這些對象保留爲對象數據成員。 B對象在多個對象之間共享,因此A應該包含最初接收的B對象而不是其副本。通過引用或指針共享對象

class A 
    { 
     public: 
      bool Initialize(B?? b); 
     private: 
      B?? m_B;  
    } 

對象B必須存在。因此,我認爲通過引用傳遞它,而不是傳遞指針,如果B爲NULL,則失敗Initialize()。

m_B的唯一代名詞是指針B的類型(它不能作爲B的引用,因爲B的初始化並不是在A c-tor中完成的)。因此,初始化應該看起來像:

bool A::Initialize(B& b) 
{ 
    m_B = &b; 
    .... 
} 

這樣可以嗎?

UPD:

  1. 的代碼是不是新的,我只是想 「修理」 的一些問題。 其實我不是在談論一些具體的A和B類,而是關於在我的代碼庫中接近問題的一種方式。代碼廣泛傳遞指向B的指針,並在Initialize()中驗證它是否爲NULL。

  2. 將B傳遞給A的C-tor並不總是一個好的選擇。還有其他參數傳遞給A,在A創建時不存在。因此,我不想將部分參數傳遞給A-tor,其餘部分傳遞給A :: Initialize()。

  3. shared_ptr也可以是「NULL」,因此將它傳遞給A :: Initialize()與傳遞指向B的指針沒有區別,在這方面,如果B是強制的,Initialize()dos的聲明不會聲明不。在我的情況下,我想通過參考B來表達它。

  4. 我們的代碼目前並未使用boost。所以,雖然shared_ptr比只傳遞原始指針更好的解決方案,但我提出的解決方案可能被認爲是不好的,但仍然是解決方案。

+2

你不應該有一個名爲Initialize()的函數 - 你應該有一個構造函數。 – 2009-12-06 17:38:58

+0

您可以使用bcp將單個組件從boost中提取出來:http://www.boost.org/doc/libs/1_41_0/tools/bcp/bcp.html – 2009-12-06 18:58:35

回答

1

我會留指針。 這裏引用只是發送錯誤信息。

不要使用引用的情況下爲對象,當你計劃採取指針對象 並保持或共享,在C++的引用是允許的東西像運算符重載 等 主要原因和拷貝構造函數工作用於用戶定義的類型。 如果沒有它們,將很難提供這種功能,其語法 與內置類型沒有區別。

但在這種情況下,你並不是想模仿內置類型。 您正在通過指針和 通常使用的對象上操作,即使通過幾個不同的指針共享。 因此應該明確說明

b爲NULL,請務必使用assert(b)(或類似結構) 強制合同並停止無效的程序。 (我不會拋出異常 即使您忘記了C++中的異常問題,您是否打算在您的代碼中捕獲並處理此類異常?) 我也將這樣的斷言添加到所有使用的代碼m_B 萬一有人忘了打電話A::Initialize()

使用引用來確保指針不爲空,可能會失火。 在大多數實現中,您可以從NULL或懸空指針 引用,而不會產生任何錯誤。 只有當您嘗試使用此引用時,您的應用程序纔會失敗。 所以如果有人不小心讓你B *pb等於NULL, 你可以撥打pa->Initialize(*pb)並沒有任何反應。 除pa->m_B現在爲NULL。

是否使用類似boost::shared_ptr的東西取決於您和您的內存策略 管理。 這是一個完全不相關的問題。

+1

對不起,我完全不同意。通過指針說「這可以是可選的」。建議您爲null聲明null意味着您需要記錄這樣一個事實,即該函數雖然接受了指針,但必須採用不能爲null的指針。接受引用說「這不是可選的」;你的論點不使用引用,因爲它可能是空的,恕我直言,最有可能成爲你的問題,因爲你的設計被破壞,因爲你拿一個指針,你應該參考,你沒有強制執行可選或必需的參數性質。 ;) – 2009-12-06 21:16:39

+0

放鬆,有時人們不同意你。 – 2009-12-07 07:38:35

+0

你說得對。 我真的不知道爲什麼我甚至會爲此爭論。 我說我的意見,提供了一些論據,它應該是它。 對於我以後的評論有些粗魯和毫無意義,我很抱歉。我應該刪除它們。 – 2009-12-07 18:35:23

0

我會用boost :: shared_ptr去。如果你使用引用,你可能不得不擔心引用的範圍,如果你使用一個普通的指針,你會遇到內存管理的麻煩。誰將刪除B?

也許你只是反思一下你的計劃:你真的需要分享這個對象還是一個B型的拷貝足夠嗎?如果B將被其他類更改並且這些更改需要被其他類所知,則需要一個shared_ptr。

+2

您如何知道它是動態分配的? – 2009-12-06 17:43:48

2

如果B是可選的,那麼它可以表示爲一個指針。如果需要B,那麼它應該被表示爲參考。

如果可能,儘量避免使用初始化方法的「兩階段構造」。如果不能在內部完成對A的處理,則需要將B視爲可選項,並將其作爲指針存儲,並在任何您想要使用的地方進行測試。

如果你的初始化方法(或理想的構造函數)需要一個B,那麼你應該把它作爲參考傳入。

這一切都假設你知道誰實際上擁有B;也許B擁有A的實例並將它們初始化爲對其自身的引用,或者B可能擁有所有引用該實例B的A的實例。

如果A自己B的對象聯合那麼你應該使用類似boost :: shared_ptr的東西來明確共享所有權;假設B是動態分配新的。

+0

我不同意。你很困惑你如何將對象與他們的一生聯繫起來。兩者都應該是明確的,都不需要關聯。說它應該是一個指針,因爲它是一個指針,可能會變成無效的是虛假的;所有東西都可以用地址(指針)表示,如果你不管理它的生命週期,所有東西都可能失效。在這種情況下,代碼被賦予一個必須存在的對象的引用;所以請使用參考。在代碼中,由於兩階段初始化,對象是可選的,所以使用一個可以是有效對象或null的指針。 – 2009-12-07 08:30:25

+0

嗯,現在,以前的評論已被刪除,似乎我在跟自己說話...... – 2009-12-16 11:09:08

+0

對不起。我只是覺得我的評論的語氣有些粗魯,並且被刪除了。也許太快了。 – 2009-12-16 17:00:07

0

我相信你應該使用構造函數而不是使用Initialize方法。

把B傳遞給A的C-tor並不總是 不錯的選擇。還有其他 參數傳遞給A,而不是 存在於A創建時。因此,我不想將 參數的一部分傳遞給A-torr,其餘部分則通過 A :: Initialize()。

您是否聽說過預構造?

這裏是你可以做的,而不是什麼一個例子:

class IsEmpty{}; 
class A 
{ 
    B *b_; 
    int *c_; 
    char *d_; 

    void Initialize(B *b) 
    { 
     b_ = b; 
     c_ = b_->Getc(); 
     d_ = b_->Getd(); 
    } 

public: 
    A(B *b) 
    : b_(0), c_(0), d_(0) 
    { 
     if(b == 0) throw IsEmpty(); 
     Initialize(b); 
    } 
}; 
1

傳遞B中引用說,B的壽命長於壽命(或時間去初始化)A的如果是這種情況下,你應該通過rerefence。在內部,您也可以將參考文件存儲在Boost reference wrapper(但是這是提升,所以可能不是一個選項)。

如果您傳遞指針,並且您確定它們應該永遠不爲NULL(如果程序正確),那麼請使用assertions而不是if-clause來檢查該指針。

我也有時有你想要的szenario,通常使用你提出的解決方案。這是最簡單的一個。

根據類的複雜性和設計,還可以使用state pattern的變體,其中描述「初始化」狀態的狀態對象是在初始化方法中構建的。在這種情況下,您可以將引用傳遞給狀態對象的構造函數。這可能有點矯枉過正(C++中的狀態模式有相當多的鍋爐板,所以確保它值得),並且需要大量的重構,但它可能以某種方式幫助你。

0

如果可能的話,我肯定會避免使用引用作爲類的成員。有一百萬種方法可能會讓你煩惱。如果你這樣做,你應該使用初始化列表,但這是你應該避免像瘟疫一樣的另一個功能。它適用於簡單的情況,但它可能會導致嚴重的問題。