2016-07-15 5 views
1

これは愚かな質問かもしれませんが、私はちょっと混乱しないようにしたいと思っています。私は、この構造体があるとします。どのようにスマートポインタなしでダブル削除を防止するには?

struct Foo{ 
    struct Bar { virtual int calc(int x) = 0; }; 
    Bar* barX; 
    Bar* barY; 
    int x,y; 
    Foo(Bar* bx,Bar* by) : barX(by),barY(by) {} 
    void process(int xx,int yy){ 
     x = barX->calc(xx); 
     y = barY->calc(yy); 
    } 
    ~Foo(); 
}; 

struct IDBar : Foo::Bar { int calc(int x) { return x; } }; 

int main() { 
    IDBar* b = new IDBar(); 
    Foo f = Foo(b,b); 
    Foo f2 = Foo(new IDBar(),new IDBar()); 
} 

私は(すなわち無smartpointers)C++ 11を使用することはできません、と私は100%を確認していない... が、これは両方を削除する正しい方法(または、おそらく唯一のものです

Foo::~Foo(){ 
    if (barX == barY){ delete barX; } 
    else { delete barX; delete barY; } 
} 

:)Barオブジェクトの?

PS:FooBarオブジェクトを所有しているため、削除する責任があります。コンストラクタに渡されたBarは、他の目的には使用されません。実際にBarは、ただ1つのFooにしか属していません(私は後で実現する欠陥ですが、それは今のところうまくいきます)。さらに、Fooはコピーされていないはずです(多分私はそれを明示的に防ぐべきです)。

+2

誰がバーを所有していますか? –

+0

ブーストスマートポインタはどうですか? – KIIV

+0

@KarolyHorvath Fooがバーを所有しています。 – user463035818

答えて

1

私はTaztingoに少し不一致があります。オブジェクトが渡されたリソースの所有権を取得することは不合理ではありません。これはあらゆる種類の現実世界のコードで発生します。クラスがコンストラクタに渡されるリソースの所有権を取得するという事実が文書化されています。誰かが文書を参考にせずにクラスを不適切に使用した場合、彼らは足で自分自身を撃っている。

しかし、これはエラーが発生しやすく、これらの種類のエラーを検出したり、そのようなエラーが発生しないようにしたいと考えています。もしFooがリソースを所有していると他の誰も思っていないことを保証する方法があれば、私たちはやっています。 C++ 11では、これはstd::unique_ptrで簡単です。以前のC++標準では、std::auto_ptrがあります。以前のC++の標準は移動コンストラクタを持っていませんが、std::auto_ptrは同様に、割り当て時に古いstd::auto_ptrからリソースを解放するか、新しいstd::auto_ptrにコピーすることによって機能します。

std::auto_ptrをお勧めします。

クラスFooの両方のコンストラクタパラメータに同じリソースが明示的に渡される場合は、std::auto_ptr<Bar>の1つだけを受け入れる新しいコンストラクタを作成します。

最後に、Fooをコピーできないようにするには、コピーコンストラクタと代入演算子を両方ともprivateとして宣言します。

+0

@ tobi303:あなたが好きな答えを変えました。しかし、ユーザーが2つのオブジェクトFoo(a、b)とFoo(b、c)を同時に扱うことができるユースケースを提供したい場合は役に立ちません。 – Roland

+0

@Rolandあなたは何を意味するのか分かります。しかし、このユースケースはとにかくサポートされていません。私は、 'Foo'が渡されたポインタの排他的所有権を持っていると考えているからです。' b'を2つの 'Foo'に渡すと、2人の所有者があります。 –

1

いいえいいえいいえ。 god no

Foo::~Foo(){ 
     if (barX == barY){ delete barX; } 
     else { delete barX; delete barY; } 
    } 

オブジェクトが自己によって割り当てなかったメモリを削除することは非常に危険です。それらのオブジェクトを所有しているものは、それらを削除する必要があります。あなたのケースでは、メインは、割り当てられたオブジェクトを削除する責任があります。

int main() { 
    IDBar* b = new IDBar(); 
    IDBar* b2 = new IDBar(); 
    IDBar* b3 = new IDBar(); 
    Foo f = Foo(b,b); 
    Foo f2 = Foo(b2,b3); 
    delete b; 
    delete b2; 
    delete b3; 
} 

メモリ管理を処理するオブジェクトの完全な例は、LinkedListです。 LinkedListはノードを自己内部に作成します。ユーザーはそれらの知識がなく、代わりにTを挿入するだけです.LinkedListは、削除されると削除します。 LinkedListを作成したため、LinkedListの削除のみ担当します。

std::list<MyObject*> list; 
MyObject* object = new MyObject; 
list.push_back(object); 
//The list isn't going to delete object because it doesn't own it 
delete object; 
+2

一般的に私は全ての帽子に書かれていて、それと別にでもアレルギーがあります。 ... "。所有権は 'Bar 'をコンストラクタに渡すと' Foo'によって取得されるため、 'Foo'はそれらを削除し、他の誰も削除しないでください。 – user463035818

+0

なぜFooはそれを所有していないのですか? – Taztingo

+0

ユーザがどの種類の 'Bar'をインスタンス化するかを選択する必要があるので – user463035818

1

あなたが建設を主張し、タジンゴのデザインルールに耳を傾けることができない場合、答えはイエスです:それは正しい方法です!

そして、Fooクラスとそのコンストラクタの強力なAPIドキュメントを作成して、オブジェクトバーのライフタイム責任を引き継ぐようにします。

+0

私はこの答えが好きです。 – Taztingo

+0

私はその "ルール"に留意することができましたが、私はそれを理解できません。 – user463035818

+0

@ tobi303:Tazingoは、2つのオブジェクトFoo(a、b)とFoo(b、c)を同時にインスタンス化できないため、強力なAPI記述が必要です。 – Roland

1

私は、比較が完全ではないと主張したいと思います。ちょうどあなたが3つのポインタを持っていると想像してください。

deleteが二重に表示されないようにするには、deleteを1つだけ呼び出してください。シナリオを考えてみましょう:

  1. メモリのプールを割り当てます(何千ものオブジェクトを割り当てるとしましょう)。これは、新しいPoolAllocator<T>クラスの中のどこかで通常のnewコールを介してヒープ上に割り当てられ、そのデクタクタ内でdeleteに割り当てられます。
  2. プールを実装して、Tのメモリを返す関数void* getMemory<T>()をサポートし、内部ポインタを進めます。
  3. Tが呼び出されたものは、プールに用意されているメモリのプレースメントでのみ作成できることを確認してください。

最後に、メモリを心配する必要はありません。プールオブジェクトは、ヒープ上に内部構造を持つ通常のスタック変数にすることができます。

それ以外の場合、proto-smartポインタを実装することを禁止していますか?

関連する問題