1

コピー コンストラクターおよび/または代入演算子で動的配列 (コンストラクターで割り当てられた) の割り当てを解除する必要がありますか?

struct Test
{
  const size_t n;
  int* xs;

  Test(const size_t n)
    : n(n)
    , xs(new int[n])
  { }

  Test(const Test& other)
    : n(other.n)
    , xs(new int[n])
  {
    memcpy(xs, other.xs, n * sizeof(int));
  }

  Test& operator=(const Test& other)
  {
    n = other.n;
    delete[] xs;
    xs = new int[n];
    memcpy(xs, other.xs, n * sizeof(int));
  }

  ~Test()
  {
    delete[] xs;
  }
};

void main()
{
  Test a(10);
  Test b(a);
  Test c(20);
  c = b;
}

ご覧のとおりdelete[]、代入演算子の実装で配列を使用する必要があると思います (割り当て先のオブジェクトの構築中に、配列が既にどこかに割り当てられているため)。また、オブジェクトはまだ構築されていないため、オブジェクトのコピー構築中に配列の割り当てを解除する必要はないと思います。

問題は、Application Verifier の下で上記のアプリケーションを実行すると、メモリ リークがあるかどうかに関係なく、メモリ リークが表示delete[]されないことoperator=です。どちらの場合でも、アプリケーションは問題なく動作します。

では、delete[] xsコピー コンストラクター、代入演算子、またはその両方を使用する必要がありますか?

4

1 に答える 1

0

一般に、手動のメモリ管理はお勧めできません。やるべきではありませんstd::vector<>。そうしない正当な理由がない限り、または他のコンテナ クラスを優先する必要があります。これは言った...

では、コピー コンストラクター、代入演算子、または両方で [] xs を削除する必要がありますか?

その配列への最後のポインタを失う前にdelete[]、配列を割り当てる必要があります。new[]そうしないと、漏れます。

実際には、削除する配列はクラスによって所有およびカプセル化されているため、これdelete[]は代入演算子のオーバーロードでそれを使用する必要があることを意味します (ポインターが新しい配列に割り当てられる前に、そのため、既存の唯一の参照が失われます)。前のもの) およびデストラクタ (オブジェクトを破棄し、カプセル化された配列への既存の参照のみを失う場合)。

あなたが言うように、コピーコンストラクターは構築ルーチンであり、ポインターは以前に割り当てられたリソースを参照していませんでした (実際、ここには「以前」はなく、オブジェクトの寿命は始まっていません):したがって、それだけではありませんここまでする必要はありませんdelete[]。間違っています。

また、ダングリング ポインターと未定義の動作の可能性を回避するために、クラスがカプセル化された配列の唯一の所有者であることを確認する必要があることに注意してください。それ以外の場合、クラスの外部のコードがdelete[]それを可能にするか、ダングリングになるポインターをクラスに保存します。したがって、xsデータ メンバーを作成しないでくださいpublic

于 2013-03-22T10:27:51.807 に答える