2
#include <iostream>
using namespace std;

class Exem {
    int *a;

    public:
        Exem() { a = new int; *a = 0; };
        Exem (int x) { a = new int; *a = x; };

        ~Exem () { delete a; };

        int f (void);

        Exem operator+ (Exem);
};

int Exem::f (void) {
    return *a * 2;
}

Exem Exem::operator+ (Exem nimda) {
    Exem aux;

    *aux.a = *a + *nimda.a;

    return aux;
}

int main() {
    Exem adabo(1);
    Exem inakos(2);

    adabo = adabo + inakos;

    cout << adabo.f();
    cin.get();
}

これは私のコードであり、問​​題を紹介するために作成されたサンプル クラスです。main() の出力は、理論上は '6' になりますが、実際に表示されるのは無意味な数値だけです。

これはどうやらクラスのデストラクタに関係しているようです。私が理解したことから、これは operator+ 関数の最後であまりにも早く呼び出されます - aux は実際に渡される前に失われます。~Exem() をコメントすると、プログラムを期待どおりに実行できるため、このような結論に達しました。

Embarcadero RAD Studio でまったく同じコードをコンパイルしようとすると、うまくいくので、これはこれら 2 つのコンパイラに関係していると推測しています。

4

1 に答える 1

2

Exem動的に割り当てられたメンバー変数があるため、コピー コンストラクターと代入演算子を明示的に定義する必要があります。

コピー コンストラクターと代入演算子がクラスに対して明示的に定義されていない場合、コンパイラーはこれらの既定のバージョンを生成します。これは、メンバーが動的に割り当てられたクラスには適していません。デフォルトで生成されたバージョンが不適切である理由は、メンバーの浅いコピーを実行するためです。の場合Exem、 のインスタンスがコピーされると、 の複数のインスタンスがという名前の同じ動的に割り当てられたメンバExemを指しています。インスタンスの 1 つが破棄されると、他のインスタンスはポインタがぶら下がり、未定義の動作のままになります。intaa delete

3 のルールを参照してください。

の簡単な修正は、 からExemに変更することです。デフォルトのコピー コンストラクタ、代入演算子、およびデストラクタは正しいでしょう。aint*int


引数を変更しないExem::operator+()ため、パラメータを取る必要があることに注意してください。const Exem&

于 2012-10-12T19:47:55.027 に答える