1

フィールドの1つとしてクラスBへのポインターを持つクラスAがあります。

class A {
private:
    B *ptr;
public:
    A(B*);
    A();
    ~A();
}

A::A(B *ptr)
{
    this->ptr = ptr;
}

A::A()
{
    this->ptr = new B();
}

A::~A()
{
    delete this->ptr;
}

new によって割り当てられた場合にのみ、デストラクタに B を削除させたいのですが、ポインタの起点を格納するフラグを設定することによってのみこれを行うことができます (そのため、A の構築中に ptr が割り当てられた場合にのみ delete が呼び出されます)。または、より洗練された解決策がありますか。つまり、任意のポインターで delete を呼び出すことができます (渡されたポインターが new を使用して割り当てられた場合、それも削除されることはわかっていますが、ポインターがスコープから渡された場合A のコンストラクターが呼び出され、明らかにこれを削除することは未定義です)?

4

4 に答える 4

3

または、よりエレガントなソリューションがあります

いいえ、そうではありません。このポインタの所有者を明確に文書化する必要があります。あなたのクラスのように見えるので、ptr自分で構築できますか?

#include <memory>

class A {
private:
    std::unique_ptr<B> ptr;
public:
    A(some_data args) 
        : ptr(new B(args)) { };
    A();    
}

クラスがポインタを所有していない場合でも問題ありませんが、割り当てを解除しないでください。そうdealloc_on_destructしないと、何をすべきかを知るために外部 (つまり ) にフラグを設定する必要があり、これが面倒になる可能性があります。

于 2012-09-17T17:15:10.950 に答える
3

より洗練された解決策は、所有モデルが異なるクラスを持たないことです。この場合、クラスによって所有されているものと所有されていないものがあります。これら 2 つのアイデアを同じクラス タイプに混在させないでください。(最小の驚きの原則に違反することによって) ユーザー/クライアントを混乱させるだけです。

必要なさまざまな動作を備えた個別のクラスを作成するか、所有権モデルを選択してクライアントを強制的にそれに固執させます (デフォルト以外のコンストラクターで所有権を渡して転送するか、自己割り当てを許可しないでください)。

于 2012-09-17T17:18:34.167 に答える
1

他の人が言うことは別として(この設計は避けてください):この設計を絶対に避けられず、所有している場合と所有してBいない場合があり、どのコンストラクターが呼び出されるかによって異なるこの面白いクラスが必要な場合は、あなたはそのように使うことができますunique_ptr(またはshared_ptr):

void delete_it(B*) { std::default_delete<B>()(t); }
void do_nothing(B *t) {}

class A {
    unique_ptr<B, void(*)(B*)> ptr;
  public:
    A(B *ptr) ptr(ptr, do_nothing) {}
    A() ptr(new B(), delete_it) {}
    // no need for destructor
    // hence also no need to worry about copy constructor or assignment
};

「生のポインタとフラグ」よりも優れている理由は、削除とコピーを実装する必要がないためです(C ++ 11で移動します)。パフォーマンスの点では「生のポインタとフラグ」よりも悪いかもしれませんが、ほとんどの場合、それについて心配する必要はありません。正当な理由がある場合は、戻って追加の作業を行うことができます。バイナリ互換性が損なわれる可能性はありますが、切り替えるためにクラスのソースインターフェイスを変更する必要はありません。

于 2012-09-17T17:49:01.860 に答える
1

あなたが提供したコードだけでは質問に答えることはできません。本当の問題は、なぜポインターを受け入れるかどうか、およびポインターが渡された場合にメモリを所有するのは誰かということです。

オブジェクトが特定のドメインで何をすべきかによって、さまざまな選択肢があります。たとえば、呼び出し元と所有権を共有できる場合shared_ptrは を使用し、オブジェクトの所有権を保持する場合は を使用しunique_ptrて、オブジェクトが所有権を取得することをインターフェースで明確にします。所有権を共有しない場合は、オブジェクトへの参照を渡すことを検討してください (内部的にポインターを格納している場合でも)。この場合、所有権と実際の使用を分離できます。

// option 1: shared ownwership
class A {
   std::shared_ptr<B> ptr;
public:
   A( std::shared_ptr<B> const & p ) : ptr(p) {}
   A() : ptr( std::make_shared<B>() ) {}
};
// option 2: grab ownership
class A {
   std::unique_ptr<B> ptr;
public:
   A( std::unique_ptr<B> p ) : ptr( std::move(p) ) {}
   A() : ptr( new B(); }
};
// option 3: no ownership (unless we create the object)
// (separating concerns: ref to access the object, ptr to manage it)
class A {
   std::unique_ptr<B> ptr;   // only ownership
   B * ref;
public:
   A( B & b ) : ptr(), ref(&b) {}
   A() : ptr( new B() ), ref(ptr.get()) {}
   // Internally use 'ref' to access the object the destructor will delete it 
   // if needed
};
于 2012-09-17T17:28:30.933 に答える