2015-04-02 76 views
1

我宣佈一個類型像C++:定製刪除狀態

template <typename T> 
using SmartPtr = std::unique_ptr<T, MyDeleter>; 

在某些特定情況下,我想算到對象的引用,並有條件地刪除它時,指針會超出範圍。

我知道有一個的std :: shared_ptr的類,但我有一些對象我想通過一個通用的接口來訪問。這些對象中的一些屬於它們的類,其他類具有工廠方法,可以產生它們創建的對象的所有權。

我的問題是:

  • 是否SmartPtr類型的每個指針有一個自己的,個人MyDeleter對象?
  • 是具有多個std::unique_ptr指點下對同一個對象被認爲是不好的編碼的做法呢?即使我使用自定義刪除器?

我覺得使用shared_ptr而不使用刪除器是錯誤的,因爲類擁有的對象不能被刪除,因爲它們不是通過new創建的。它們是類的一部分,是類的成員。並非所有SmartPtr指向的對象都是使用new運算符創建的。

+4

_「是否有多個std :: unique_ptrs指向同一個對象」_單詞「unique」是贈品,不是嗎?你能否進一步解釋爲什麼'std :: shared_ptr'不適合你? – 2015-04-02 14:48:57

+0

因爲某些對象不共享並且不可以。我需要他們的移動語義。其他人可以共享。我想通過一個通用的指針類型來訪問所有這些對象。 – biowep 2015-04-02 14:50:41

+2

對我來說這似乎很可笑。你爲什麼認爲你需要這個? – 2015-04-02 14:53:18

回答

2

你想有一個指針成員可能會或可能不擁有它指向的東西?簡單,關注點分離:

std::unique_ptr<T> maybe_owning; 
T* always_pointing; 

constructor(const T& copy_and_own) 
    :maybe_owning(new T(copy_and_own)) 
    ,always_pointing(maybe_owning.get()) 
{} 
constructor(T* just_reference) 
    :maybe_owning() 
    ,always_pointing(just_reference) 
{} 
void do_task() { 
    always_pointing->thing(); 
} 

你有一個指針總是指向數據,並不在乎絲毫的所有權。
你也有一個智能指針,可以有條件地用於擁有。
解決了所有問題,沒有瘋狂的代碼。

我使用此通常實際上,一個fstream,可能或可能不打開一個文件,並且一個istream&有時連接到fstream和有時cin,那麼我可以從讀任一源相同。

2

這是一個工作「也許刪除,也許不是」類:

enum class should_delete { 
    yes, 
    no, 
}; 
struct maybe_delete { 
    should_delete choice = should_delete::yes; 
    template<class T> 
    void operator()(T* t){ 
    if (choice!=should_delete::no) 
     delete t; 
    } 
    maybe_delete() = default; 
    maybe_delete(should_delete c):choice(c) {} 
    maybe_delete(maybe_delete const&)=default; 
    // move in terms of copy, then clear state to default: 
    maybe_delete(maybe_delete&& o):maybe_delete(o){ 
    o.choice = should_delete::yes; 
    } 
}; 
template<class T> 
using maybe_unique_ptr = std::unique_ptr<T, maybe_delete>; 

的是,可能是唯一的指針類型。

live exmaple

纔能有指針的問題不刪除對象與{ptr, should_delete::no}建設。 (移動)這樣的maybe_unique_ptr的副本將具有適當的狀態。

注意.reset(ptr)可能是危險的,因爲對象獲得的前那兒有什麼缺失狀態。我保證從maybe_unique_ptr移動到具有相同的狀態作爲與平凡構造的小心maybe_delete移動ctor。


話雖這麼說,如果你想要寫一個侵入智能指針,我不會做它作爲原料unique_ptr

如果你看一下std::shared_ptr,他們有「上帝模式」的構造函數:

shared_ptr<T>::shared_ptr(T*, shared_ptr<U>) 

,它可以讓你有一個共享PTR到T所有的引用計數轉發到一個完全不同的共享,PTR。這是爲「會員」共享師生比(其他用途) - 如果你有一個結構X與成員Y,你可以有一個共享PTR到Y實際引用計數封閉X結構。

對於侵入智能指針,我會寫一個智能指針。它會存儲一個T*和一個用於清理的「範圍守衛」類型的對象,該對象執行遞減操作(範圍守護甚至可以是具有遞減驅逐程序的引用計數接口的unique_ptr)。做一個智能指針樣板(幾十行)。複製時,克隆範圍守衛和T*。在移動中,移動指針和範圍守護(並清除源)。

具有包裹原料T*具有空ref_count(如果需要)的構造,或一T*ref_count界面,或這兩者,作爲酮。

如果包含對象有引用計數,我會試圖使用它,只是爲了及早發現關閉問題。


bonus version with arbitrary deleter guarded by maybe_delete。例如,這可以允許您有條件地重新計算遞減量,而不會將這兩個操作混合太多。使用空基類優化來防止浪費的空間(因爲std::default_delete爲空)。