2012-01-03 71 views
47

我寫過一個靜態工廠方法,它返回從另一個數據對象填充的新Foobar對象。我最近一直癡迷於所有權語義,並且想知道如果我通過讓這個工廠方法返回unique_ptr來傳達正確的信息。返回unique_ptr用於像所有權語義一樣的原始指針的不良做法?

class Foobar { 
public: 
    static unique_ptr<Foobar> factory(DataObject data); 
} 

我的意圖是告訴客戶端代碼他們擁有指針。沒有智能指針,我只會返回Foobar*。但是,我希望強制刪除此內存以避免潛在的錯誤,因此unique_ptr似乎是一個合適的解決方案。如果客戶想延長指針的壽命,他們只是叫.release()一旦他們得到了unique_ptr

Foobar* myFoo = Foobar::factory(data).release(); 

我的問題有兩個部分:

  1. 請問這種做法傳達正確的所有權語義?
  2. 這是一個「不好的做法」返回unique_ptr代替原始指針?
+0

您正在返回一個unqiue_ptr告訴客戶端他們擁有指針?這與我所期望的完全相反(因爲他們必須明確地獲得唯一指針的所有權)。 – jknupp 2012-01-03 21:54:53

+1

您可能想使用移動語義(如果您能夠使用C++ 11)。有了這個,用戶可以決定如何延長工廠創建的對象的生命週期。 – evnu 2012-01-03 21:57:35

+1

@evnu這是你自動完成的事情,不是嗎? – 2012-01-03 22:20:09

回答

58

從一個工廠方法返回一個std::unique_ptr是蠻好的,應該是一個值得推薦的做法。它傳遞的信息是(IMO):您現在是此物件的唯一擁有者。此外,爲了您的方便,對象知道如何摧毀自己。

我認爲這比返回一個原始指針(客戶端必須記住如何以及如何處理這個指針)好得多。

但是我不明白你的關於釋放指針延長它的生命週期評價。總的來說,我很少看到任何理由罵release在智能指針,因爲我覺得指針應該總是通過某種RAII結構(只是這裏我打電話release是把指針在不同的管理數據結構的唯一情況,例如管理一個unique_ptr與一個不同的刪除器,後我做了一些事情,以保證額外的清理)。

因此,客戶端可以(也應該)僅存儲所述unique_ptr某處(例如另一unique_ptr,這一直移動從返回的一個構造的),只要它們需要的對象(或一shared_ptr,如果他們需要多個拷貝的指針)。因此,客戶方的代碼應該看起來更像是這樣的:

std::unique_ptr<FooBar> myFoo = Foobar::factory(data); 
//or: 
std::shared_ptr<FooBar> myFoo = Foobar::factory(data); 

個人而言,我也爲返回的指針類型添加typedef(在這種情況下std::unique_ptr<Foobar>)和或用於刪除器(在這種情況下的std :: default_deleter)至你的工廠對象。如果稍後決定更改指針的分配(因此需要使用另一種銷燬指針的方法,該指針將作爲第二個模板參數std::unique_ptr可見),這會更容易。 所以我會這樣做:

class Foobar { 
public: 
    typedef std::default_deleter<Foobar>  deleter; 
    typedef std::unique_ptr<Foobar, deleter> unique_ptr; 

    static unique_ptr factory(DataObject data); 
} 

Foobar::unique_ptr myFoo = Foobar::factory(data); 
//or: 
std::shared_ptr<Foobar> myFoo = Foobar::factory(data); 
+3

我不是故意提到'release()'是誤導性的或令人困惑的,對不起。這個新代碼正在進入一個相當大的現有應用程序(一百二十萬行C++),它不使用任何智能指針(COM除外)。我知道我的團隊中的其他人會擔心,如果遺留代碼使其有效「需要」,那麼如果沒有合理的方法可以達到原始指針。當然,我會給出適當的警告,並建議在可能的情況下堅持使用unique_ptr/shared_ptr。我真的很喜歡你的typedef想法,它將你的答案與James McNellis'區別開來。感謝您的見解。 – 2012-01-04 13:26:44

17

A std::unique_ptr唯一擁有它指向的對象。它說:「我擁有這個東西,而其他人沒有。」

這就是你想什麼來表達:你說「這個函數的調用者:你現在是此對象的唯一擁有者,用它做什麼,請你,它的壽命是你的責任。」

+0

的確,但爲什麼不讓它返回一個'std :: shared_pointer <>'?它達到了相同的效果,但允許指針的多個副本。 – 2012-01-03 21:59:36

+8

@AndréCaron:如果您只想將所有權轉讓給調用者,爲什麼強制使用'std :: shared_ptr'?如果調用者想要將對象的所有權賦予「std :: shared_ptr」(或者如果調用者想要的話,則爲其他類型的智能指針)。 – 2012-01-03 22:01:04

+7

@AndréCaron:原因基本上是表現。工廠無法知道客戶端是否會將'std :: shared_ptr'添加的功能放在'std :: unique_ptr'上,所以爲什麼會犧牲一些功能的性能,這可能不是必需的。由於'shared_ptr'可以構造並從'unique_ptr'分配,所以確實沒有好處。 – Grizzly 2012-01-03 22:11:12

6

它確切地傳遞了正確的語義,並且是我認爲C++中的所有工廠都應該工作的方式:std::unique_ptr<T>不強加任何類型的所有權語義,並且它非常便宜。

相關問題