2013-09-27 93 views
80

我有一個unique_ptr成員的類。如何在std :: unique_ptr成員中使用自定義刪除器?

class Foo { 
private: 
    std::unique_ptr<Bar> bar; 
    ... 
}; 

Bar是一個具有create()函數和destroy()函數的第三方類。

如果我想使用與它std::unique_ptr在一個獨立的功能,我可以這樣做:

void foo() { 
    std::unique_ptr<Bar, void(*)(Bar*)> bar(create(), [](Bar* b){ destroy(b); }); 
    ... 
} 

有沒有辦法用std::unique_ptr作爲類的成員,要做到這一點?

回答

78

假設createdestroy是免費的功能(這似乎是從OP的代碼片段的情況下),具有以下特徵:

Bar* create(); 
void destroy(Bar*); 

你可以寫你Foo類這樣

class Foo { 

    std::unique_ptr<Bar, void(*)(Bar*)> ptr_; 

    // ... 

public: 

    Foo() : ptr_(create(), destroy) { /* ... */ } 

    // ... 
}; 

請注意,您不需要在此處編寫任何lambda或定製刪除程序,因爲destroy已經是刪除程序。

+86

使用C++ 11 'std :: unique_ptr ptr_;' – Joe

3

您可以簡單地使用std::bind與您的銷燬功能。

std::unique_ptr<Bar, std::function<void(Bar*)>> bar(create(), std::bind(&destroy, 
    std::placeholders::_1)); 

但是當然你也可以使用lambda。

std::unique_ptr<Bar, std::function<void(Bar*)>> ptr(create(), [](Bar* b){ destroy(b);}); 
33

你只需要創建一個缺失者類:

struct BarDeleter { 
    void operator()(Bar* b) { destroy(b); } 
}; 

,並提供它作爲unique_ptr模板參數。你仍然必須初始化在構造函數中的unique_ptr:

class Foo { 
    public: 
    Foo() : bar(create()), ... { ... } 

    private: 
    std::unique_ptr<Bar, BarDeleter> bar; 
    ... 
}; 

據我知道,所有的流行的C++庫正確地實現這一點;由於BarDeleter實際上沒有任何狀態,所以不需要佔用unique_ptr中的任何空間。

+4

這個選項是唯一適用於數組,std :: vector和其他集合的選項,因爲它可以使用零參數std :: unique_ptr構造函數。其他答案使用的解決方案無法訪問此零參數構造函數,因爲在構造唯一指針時必須提供Deleter實例。但是這個解決方案向std :: unique_ptr('std :: unique_ptr ')提供了一個Deleter類(struct BarDeleter),它允許std :: unique_ptr構造函數自己創建一個Deleter實例。即允許下面的代碼:'std :: unique_ptr bar [10];' – DavidF

+5

我將創建一個typedef以便於使用'typedef std :: unique_ptr UniqueBarPtr' – DavidF

60

可以在C++ 11中使用lambda乾淨地進行此操作(在G ++ 4.8.2中測試)。

鑑於這種可重複使用的typedef

template<typename T> 
using deleted_unique_ptr = std::unique_ptr<T,std::function<void(T*)>>; 

你可以寫:

deleted_unique_ptr<Foo> foo(new Foo(), [](Foo* f) { customdeleter(f); }); 

例如,一個FILE*

deleted_unique_ptr<FILE> file(
    fopen("file.txt", "r"), 
    [](FILE* f) { fclose(f); }); 

有了這個,你得到的使用RAII進行異常安全清理的好處,無需嘗試/捕捉噪音。

+1

這應該是答案,imo。這是一個更美麗的解決方案。或者是否有任何缺點,例如在定義中有'std :: function'或類似的東西? – j00hi

+6

@ j00hi,在我看來這個解決方案由於'std :: function'有不必要的開銷。與此解決方案不同,Lambda或自定義類可以內聯。但是,如果您想要隔離專用模塊中的所有實現,則此方法具有優勢。 – magras

+2

如果std :: function構造函數拋出會造成內存泄漏(如果lambda太大而不能放入std :: function對象內,可能會發生這種情況) – Ivan

相關問題