1

C++ でメモリを適切に削除/割り当て解除する方法について質問があります。

次のものがあるとします... (A、B、C、D がクラスであると仮定します。B と C はインスタンス変数 を持ちますA* a。D は 2 つのインスタンス変数を持ち、B* bそしてC* c)

A* a = new A();
B* b = new B(a);
C* c = new C(a);
D* d = new D(b, c);

B と C のデストラクタ:

B::~B() { delete a; }
C::~C() { delete a; }

D のデストラクタ:

D::~D() { delete b; delete c; }

今私が電話するとき

delete d;

「アクセス違反の読み取り場所 0xfeeefeee」が表示されます (私は Visual Studio 2010 を使用しています)。これだからだと思います

-のデストラクタは、既に割り当てが解除されている同じメモリ ( ) を 2 回D「削除」しようとしています。aa

-私は 2 つのポインタ (1 つは にB、もう 1 つは にC) を両方とも ( の ) 同じアドレスを指してaおり、D のデストラクタがb(次に を呼び出すdelete a) を削除すると、このメモリは解放済みとして設定されます。

- のデストラクタが をD削除するとc、すでに割り当てが解除されているために失敗するように、独自cに呼び出そうとします。delete aa

私はC++は比較的初めてですが、プログラミングは初めてではありません。これを調べたところ、スマート ポインター (shared_ptr など) がこれを解決できることがわかりましたが、この場合のベスト プラクティスは何ですか? 2 つの個別Aのオブジェクトを作成する必要がありましたか?

4

5 に答える 5

4

ここでの問題は、Aオブジェクトの所有者を決定することです。とは へのポインタであるため、 と の両方が自分自身を所有者Bと見なしているようです。ただし、割り当ては行わなかったので、通常は削除するべきではありません。CdeleteaA

この問題にはいくつかの解決策があります。

  1. ポインターの代わりにオブジェクトを使用する- これにより、コンパイラーが適切な処理を行うため、メモリ管理が大幅に簡素化されます。
  2. とのコンストラクター内に新しいAオブジェクトを作成します。BC所有delete aしているため、できるようになりました。これを行うときは、コピー コンストラクターと代入演算子も実装する必要があります。
  3. 所有権の暗黙的な転送を行う- これは、呼び出し元が正しく理解するのが最も難しいものです。呼び出し元がorAのコンストラクターに渡されると、呼び出し元はすぐにオブジェクト ポインターの使用を停止する必要があります。の所有権を引き継ぎ、デストラクタで削除します。BCBCA
  4. 所有するオブジェクトを渡す- と の有効期間を制御するBと、これらのオブジェクトの有効期間中にCが存在することを確認できます。Aこの場合B、 andCは を参照できAますが、デストラクタのポインタには触れません。

ご覧のとおり、言語は所有権を制御する際に多くの柔軟性を提供します。一般に、最も単純なモデルから始めて、単純なモデルがニーズに合わなくなったら、より複雑なモデルに進む必要があります。

于 2013-10-26T23:39:16.227 に答える
2

ほとんどの場合、ヒープにメモリを割り当てる必要はありません (つまり、 を呼び出す必要はありませんnew)。マネージ言語 (Java、C# など) を使用している場合、それをやめるのは難しい習慣です。設計の目標に応じて、コードは次のように記述できます。

A a;
B b(a);
C c(a);
D d(b, c);

設計でポインターと動的メモリの使用が必要な場合は、スマート ポインター ラッパー (std::unique_ptrおよびstd::shared_ptr) を使用する必要があります。この特定のケースではstd::shared_ptr、複数の場所でポインターを使用 (共有など) しているため、使用することをお勧めします。

std::shared_ptr<A> pA = std::make_shared<A>();
std::shared_ptr<B> pB = std::make_shared<B>(a);
std::shared_ptr<C> pC = std::make_shared<C>(a);
std::shared_ptr<D> pD = std::make_shared<D>(b, c);
于 2013-10-26T23:40:26.017 に答える