6

サブルーチンのスコープ外で定義する必要があるにもかかわらず、サブルーチンの最後でクラスに対してデストラクタが呼び出されるという問題があります。

これが私の問題を表示する私が持っているコードの最小部分です:

#include <iostream>
using namespace std;

class Foo {
private:

    double *array;

public:

Foo(int N) {
   array = new double[N];
   for (int i=0; i<N; i++) {
       array[i]=0;
   }
}

~Foo() {
   delete[] array;
}
};

void subroutine(Foo x) {
   cout << "Hello!" << endl;
}

int main() {
   Foo bar(10);
   subroutine(bar);
   subroutine(bar);
}

ここで、オブジェクトバーのデストラクタは、最初のサブルーチンが終了した後に呼び出されますが、そのスコープはmain()関数全体である必要がありますか?これは、2番目のサブルーチンを呼び出すと、デストラクタが再度呼び出され、メモリリークが発生することを意味します。

サブルーチンで参照を呼び出すことでこれを修正できることがわかりましたが、そもそもなぜ機能しなかったのか理解できないため、この修正にはあまり満足していません。誰かが私のためにこれにいくつかの光を当てることができますか?

ありがとう。

4

4 に答える 4

21

Foo関数にby値を渡していsubroutineます。これは、スコープを終了すると破棄される独自のコピーがあることを意味します。

void subroutine(Foo x) {
   // x is a new Foo here. It will get destroyed on exiting scope,
   // resulting in a destructor call
}

ここでの主な問題は、コピーコンストラクターを実装していないため、動的に割り当てられた配列がコピーされないことです(それを指すポインターのみがコピーされます)。したがって、Fooオブジェクトをコピーすると、各コピーが同じ配列を参照するようになります。そして、各コピーはそれを破壊しようとします。

三つのルールに従い、各Fooオブジェクトが独自の配列を所有するように、配列の「ディープコピー」を作成する代入演算子とコピーコンストラクターを実装する必要があります。

于 2012-10-05T13:15:23.110 に答える
6

バーを値でサブルーチンに渡しているため、コピーが作成されています。コピーが参照渡しになるのを避けるには:

void subroutine(Foo& x)
{
    cout << "Hello!" << endl;
}

次のようにコピー コンストラクターとコピー代入演算子をプライベートに宣言することで、クラスの偶発的なコピーを防ぐことができます。

class Foo {
private:

    double *array;

    Foo(const Foo&);
    Foo& operator=(const foo&);

public:
    ...
};

次に、代わりにコンパイルエラーが発生します。本当にクラスのコピーを作成できるようにする必要がある場合は、実際にこれらの関数を実装して「ディープ コピー」を実行する必要があります (またはstd::vector<float>、安全なコピーを含むメモリを使用して管理できるようにすることをお勧めします)。

于 2012-10-05T13:17:12.920 に答える
3

void subroutine(Foo x) {オブジェクトを呼び出すと、barコピーされます(したがって、関数の終了後にデストラクタが呼び出されます)。

を使用してみてください: void subroutine(Foo &x) {、問題なく動作するはずです。

于 2012-10-05T13:16:07.777 に答える
1

あなたが抱えている問題は、オブジェクトを値渡ししていることです:

void subroutine(Foo x) {

これは、一時オブジェクトを作成し、呼び出すたびにオブジェクトのコピー コンストラクター/デストラクターを呼び出します。

于 2012-10-05T13:16:03.940 に答える