2016-09-23 8 views
1

"Destroy()"と "Clone()"メソッドを持つ多相型(つまり、常にポインタで相互作用しています)で作業しています。それをリソースセーフタイプでラップします。ユニーク/ shared_ptrとカスタム演算子=

「Destroy()」が気にしなければならないことがあれば、独自のDeleterでunique_ptrを使うことができました。 ただし、の場合、このリソースハンドルタイプは、別のタイプのメンバーとして使用されます。他のタイプのメンバーとして使用される場合は、デフォルトで生成されたコピーおよび割り当て操作を使用してコピーできます。理想的には、私は既にリソースハンドルのデストラクタをカスタマイズして "Destroy()"を呼び出すのと同じように、リソースハンドルのコピーコンストラクタと割り当てをカスタマイズして "Clone()"を呼び出すことができます。しかし、unique_ptrとshared_ptrに関するドキュメントを見て、私はそれを可能にするものは見ません。

  1. ドキュメントに何か紛失しましたか?これを行うための既成のstdの方法はありますか?
  2. そうでない場合は、unique_ptrを拡張してコピー操作をオーバーライドする必要がありますか?
  3. また、通常のポインタセマンティクスをゼロから自分のリソースハンドルだけで作成する必要がありますか?
+2

encapsulate unique_ptr。 –

+3

'unique_ptr 'をいくつかの型でラップし、その型の移動とコピー操作を実装します。移動はデフォルトにすることができ、コピーは 'Clone'を呼び出すでしょう。 – Praetorian

+0

2つの別々のスマートポインタで管理されている2つの異なるオブジェクトで終了しない限り、本当に 'Clone()'を呼びたくはないと思います。 – Galik

答えて

3

あなたがunique_ptrshared_ptrを持つ理由の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

一つの周りにラッパーを作成することは、そのコピーで、周りにこれらのポインタをジャグリングすることは、基礎となるオブジェクトのコピーを含まない安価な操作です。

スマートポインタは、自分でoperator=をインストールする手段を実装していません。あなたの質問を理解しているので、あなたのカスタムClone()Destroy()メソッドへの呼び出しで、スマートポインタがコピーされるときにウェッジしたいと思う。

まあ、unique_ptrshared_ptrは、正しいことを行うoperator=を実装しています。

あなたのDestroy()によって行われていることは、実際にはクラスのデストラクタで実行する必要があります。それがデストラクタの目的です。次に、clone()メソッドは、独自のオブジェクトを複製するだけで、新しいunique_ptrを返す必要があります。すでにunique_ptrまたはshared_ptrがある場合は、clone()メソッドを呼び出すためにこのオブジェクトを使用して、クローンにスマートポインタを返しますオブジェクト:オブジェクトを破棄する前に呼び出されなければならない明確なDestroy()メソッドを持つ

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

// p is initialized, populated from there. 

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

は、バグの無限のパレードを生み出すための招待状です。複製されたオブジェクトを破棄するときに呼び出すことを忘れる前は、時間の問題です。

コード内にバグを作成して時間を無駄にすることを避ける最善の方法は、それらが論理的に起こらないようにすることです。オブジェクトを破壊するために何かをする必要がある場合、これはデストラクタで行う必要があります。別のオブジェクトからクローンされたオブジェクトを破棄するために余分な処理が必要な場合、そのオブジェクトにはクローンオブジェクトであることを示す内部フラグが必要で、デストラクタにはそれに基づいて適切な処理が行われます。

これが完了すると、クローンされたオブジェクトを取り除くために何かをすることを忘れて、論理的にコードが壊れてしまうことはありません。あなたは自分自身を救うことを祝福することができます。将来は、決して創造されないバグを探して時間を浪費することからです。あなたの未来の自己はあなたの過去の自己に感謝します。スマートポインタは、使用することを意図したものを使用してください。clone()は最初からスマートポインタを提供しています。

+0

'>あなたのDestroy()によって行われていることは、クラスのデストラクタで実際に行われるはずです。それがデストラクタの目的です。 ...オブジェクトを破棄する前に呼び出さなければならないDistroy()メソッドを持つことは、無限のバグのパレードを呼び出すための招待です。 ' 私はそれにすべて同意します。しかし、私のクラスではありません。私はただそれを使用しなければならない悲しいパンダです。このリソースハンドルラッパーを作成することは、そうでなければエラーが発生しやすいクラスを使用する方がはるかに安全にすることです。 –

+0

あなたはそれをサブクラス化し、この不毛の上により良いファサードを置くことができますか? –

関連する問題