2

クラスの 1 つに、次のコンストラクタ、デストラクタ、代入演算子があります。メモリリークするかどうか疑問に思っています。

MenuItem::MenuItem() {
  menu_items = new vector<MenuItem>;
}

MenuItem::MenuItem(const MenuItem &other) {
  menu_items = new vector<MenuItem>(*other.menu_items);
}

MenuItem::~MenuItem() {
  menu_items->erase(menu_items->begin(), menu_items->end());
  delete menu_items;
}

MenuItem & MenuItem::operator= (const MenuItem &other) {
  *menu_items = *other.menu_items;
  return *this;
}

私の主な関心事は代入演算子です。私はいくつかのドキュメントを見て、これを見つけました:The container preserves its current allocator, which is used to allocate storage in case of reallocation. Any elements held in the container before the call are either assigned to or destroyed.私にとって、これは私の割り当てがメモリ リークから安全であることを意味しますが、以前にドキュメントを誤解したことがあります。助けてくれてありがとう。

4

3 に答える 3

3

コードは良さそうに見えますが、動的に割り当てないでくださいvector。いずれにせよ、要素はvector動的に割り当てられるため、コンテナー自体の割り当てはほとんど使用されません。データメンバーを作成するvectorと、コードは次のようになります。

struct MenuItem
{
  std::vector<MenuItem> menu_items;
};

それ以外はすべて、コンパイラによって暗黙的に生成されます。を実行する正当な理由がある場合、私が推奨newするvector唯一の変更は、初期化にコンストラクタ初期化子リストを使用vector::eraseし、不要なためデストラクタを呼び出さないことです。

MenuItem::MenuItem() 
: menu_items(new vector<MenuItem>())
{}

MenuItem::MenuItem(const MenuItem &other)
: menu_items(new vector<MenuItem>(*other.menu_items))
{}

MenuItem::~MenuItem() 
{
  delete menu_items;
}
于 2013-07-26T14:43:52.080 に答える
2

代入演算子が原因で、プログラムにメモリ リークが発生することはありません。しかし、ベクトルをヒープ上に配置するのは非常に奇妙に感じますが、そうする理由はありますか?

実際には、含まれているオブジェクトのアロケータが例外をスローすると、メモリ リークが発生する可能性があります。説明させてください

  1. コピーコンストラクターを呼び出します
  2. を呼び出して新しいベクトルをインスタンス化しようとしますnew。これは例外をスローする可能性があり、これは問題なく、まったく問題ありません
  3. operator の呼び出しはnew成功しますが、含まれているオブジェクトのアロケーターが例外をスローします。コンストラクタで例外をキャッチしないと、コンストラクタがスローされ、デストラクタが呼び出されません->割り当てた(おそらく空ではない)ベクトルに関するメモリリーク。

C++11 を使用している場合は、次のように、コピー コンストラクター内から既定のコンストラクターに委譲することで問題を解決できます。

MenuItem::MenuItem(const MenuItem &other) : MenuItem(){
  *menu_items = *other.menu_items;
}

そうする場合、オブジェクトの割り当てに到達すると*menu_items、オブジェクトは完全に構築され(: MenuItem()いわば によって)、これがスローされると、デストラクタが呼び出されdelete menu_itemsて実行されます。

C++11 を使用していない場合

MenuItem::MenuItem(const MenuItem &other) : menu_items(NULL) {
  try{ menu_items = new vector<MenuItem>(*other.menu_items); }
  catch(...){delete menu_items;}
}

とにかく、これはおそらくより良い解決策です。

ドキュメントから引用したものは、このコンテキストでは関係ありません。コンテナが同じ関数を使用して、含まれているオブジェクトを割り当てることを意味します。

于 2013-07-26T14:36:07.073 に答える
0

メモリ エラーがないという意味では問題ないように見えます。破壊時にベクトルを削除し (最初に内容を消去する必要はありません)、コピー セマンティクスを実装して、各ベクトルが 1 つのオブジェクトによって所有されるようにします。ベクトルには正しいコピー セマンティクスも含まれているため (それ以外の場合は使用するのが危険であるため)、代入演算子は正しいです。

ただし、動的に割り当てても意味がありませんvector。メンバー変数にしないのはなぜですか?次に、そのすべてのコードを次のように単純化できます。

于 2013-07-26T14:35:06.340 に答える