2016-09-23 88 views
1

我正在使用具有方法「Destroy()」和「Clone()」的多態類型(即,我總是通過指針與它交互),並且我想以資源安全類型包裝它。unique/shared_ptr自定義運算符=

現在,如果「Destroy()」是所有我必須擔心的,那麼我可以使用unique_ptr與自定義刪除器,這將很容易。 但是,此資源句柄類型被用作另一種類型的成員,否則這種類型可以使用默認生成的副本和分配操作進行復制。理想情況下,我想定製資源句柄的拷貝構造函數和賦值來調用「Clone()」,就像我已經自定義資源句柄的析構函數來調用「Destroy()」一樣。但是通過unique_ptr和shared_ptr上的文檔查看,我沒有看到任何會讓我這樣做的東西。

  1. 我錯過了文檔中的內容嗎?有沒有現成的標準方法來做到這一點?
  2. 如果不是,我應該擴展unique_ptr並覆蓋複製操作嗎?
  3. 或者,我是否應該從頭開始編寫自己的資源句柄和所有常用的指針語義?
+2

encapsulate unique_ptr。 –

+3

將'unique_ptr '換成某種類型,併爲其執行移動和複製操作。這些動作可以默認,複製會調用'克隆'。 – Praetorian

+0

我懷疑你真的不想調用'Clone()',除非你想結束兩個不同的由兩個獨立的智能指針管理的類型的對象。 – Galik

回答

3

您可以創建包裝器std::unique_ptr

// To handle your cusstom Destroy 
struct DestroyDeleter 
{ 
    void operator(Interface* o) { 
     object->Destroy(); 
     delete object; 
    } 
}; 

using InterfacePtr = std::unique_ptr<Interface, DestroyDeleter>; 

// To handle the copy with clone: 
class wrapper 
{ 
public: 
    explicit wrapper(InterfacePtr o) : data(std::move(o)) {} 

    wrapper(const wrapper& rhs) : data(rhs.data->Clone()) {} 
    wrapper(wrapper&& rhs) = default; 

    wrapper& operator =(const wrapper& rhs) { data = rhs.data->Clone(); } 
    wrapper& operator =(wrapper&& rhs) = default; 

    const Interface* operator ->() const { return data.get(); } 
    Interface* operator ->() { return data.get(); } 

    const Interface& operator *() const { return data; } 
    Interface& operator *() { return *data; } 

private: 
    InterfacePtr data; 
}; 
0

的原因之一,對於具有unique_ptrshared_ptr是複製和周圍雜耍這些指針是一種廉價的操作,並不涉及複製基礎對象。

這就是爲什麼智能指針不能實現任何手段來安裝您自己的operator=。正如我理解你的問題,當智能指針被複制時,你想要調用自定義的Clone()Destroy()方法。

那麼,unique_ptrshared_ptr執行自己operator=這是正確的事情。

對於初學者來說,無論你的Destroy()是做什麼都應該在你的類的析構函數中完成。這是一個析構函數。然後,您的clone()方法只需要克隆自己的對象,並返回一個新的unique_ptr,因此,當您已經有一個現有的unique_ptrshared_ptr時,使用它調用clone()方法克隆該對象並返回一個智能指針指向克隆對象:

std::unique_ptr<myClass> p; // Or std::shared_ptr 

// p is initialized, populated from there. 

std::unique_ptr<myClass> new_p=p->clone(); 

具有獨特Destroy()方法必須銷燬的對象之前被調用是產卵的錯誤無盡的遊行的邀請。在銷燬克隆對象時忘記調用它只是一個時間問題。

避免用代碼中的錯誤創建和浪費時間的最佳方法是使它們在邏輯上不可能發生。如果爲了銷燬一個對象需要做些什麼,這需要在析構函數中完成。如果爲了銷燬從另一個對象克隆的對象需要做一些額外的工作,對象需要有一個內部標誌來指示它是一個克隆對象,並且它的析構函數根據這個標準來做正確的事情。

一旦完成,通過忘記做某件事來擺脫克隆的對象,將會使代碼變得邏輯上不可行。您可以祝賀自己在未來拯救自己,免得浪費時間尋找一堆現在永遠不會創建的bug。你未來的自我會感謝你的過去的自我。只需使用智能指針就可以使用,並且從一開始就有clone()爲您提供智能指針。

+0

'>對於初學者,你的Destroy()所做的任何事情都應該在你的類的析構函數中完成。這是一個析構函數。 ...在破壞對象之前必須調用一個獨特的Destroy()方法是一個邀請產生無盡的錯誤遊行。' 我同意所有這一切。但這不是我的課。我只是不得不使用它的悲傷熊貓。使這個資源句柄包裝的重點是讓這個容易出錯的類更安全。 –

+0

你可以繼承它,並在這個壞事上做得更好嗎? –