1

クラス型 Test とパラメータ付きのコンストラクタを作成しましたが、作成したコンストラクタを関数 f を介して新しいコンストラクタに割り当てようとすると、プログラムがクラッシュします。なぜだかわかる方いますか!?

コード:

class Test
{
  public:
    int number;
    int *a;
    Test(int n){
        a = new int[n];
    }
    ~Test(){
        delete []a;
    }
};

Test f(Test Ft1)
{   
     // Do something.
     return Ft1;
}

int main()
{   
    Test t1(3);
    t1.number = 5;
    Test t2 = f(t1);    
    return 0;   
}
4

2 に答える 2

2

問題は、とデストラクタが呼び出され たaときに同じ配列を 2 回削除していて、そのメンバー変数が同じメモリ位置を指していることです。を実行すると、 のコピーが作成され、 に割り当てられます。特定のコピー コンストラクターを定義していないため、コンパイラによって暗黙的に定義されています。ただし、値をコピーするだけです(期待どおりに割り当ては行いません)。t1t2t1t2aTest t2 = f(t1)t1t2anew

ベスト プラクティスとして、独自のものを追加することをお勧めします:
- コンストラクターの
コピー - 代入のコピー
(cf rule of three)

変数メンバーのa設計に関して:
- 同じ配列を指したい場合t1t2、使用できますshared_ptr
-独自の配列を持ちたい場合は、 for を使用する方がt1簡単ですt2vector<int>a

編集:生のポインターを使用する必要がある場合に備えて、コピー コンストラクターと演算子の割り当てでメモリを管理する方法の簡単な例を次に示します。それについての参考書を読むことをお勧めできますか (たとえばEffective C++ , chapter 11)。重要な概念と落とし穴について説明します。

class Test{
public:
    int number;
    int *a;
    Test(int n){
        a = new int[n];
    }
    ~Test(){
        delete [] a;
    }
    Test(const Test& that)
    {
        int size = sizeof(that.a);
        a = new int[size];
        memcpy (a, that.a, sizeof(size));
    }
    Test& operator=(const Test& that)
    {
        if (this != &that)
        {
            delete [] a;
            int size = sizeof(that.a);
            a = new int[size];
            memcpy (a, that.a, sizeof(size));
        }
        return *this;
    }
};

Test f(Test Ft1){   
    //do something
    return Ft1;
}

int main(){ 
    Test t1(3);
    t1.number = 5;
    Test t2 = f(t1);
    // Test t3(t1);  // calls copy constructor
    // t3 = t1; // calls assignment operator
    return 0;   
}
于 2013-10-26T06:44:52.227 に答える
2

あなたの問題の原因は、「バイナリコピー」と呼ばれるものがあることです。特別な代入/コピー コンストラクターが定義されていない場合、このバイナリ コピーが開始されます。オブジェクトの 1 つが別のオブジェクトにコピーされると、ポインターが上書きされ、コピー先オブジェクトの元の配列がリークされるため、2 つの異なるインスタンスが同じ配列を所有し始めます。

コンパイラは、あるオブジェクトの内容を別のオブジェクトに簡単にコピーしても問題ないと考えていますmemcpy()(図は少し単純化されていますが、本質的には私が書いていることは正しいです)。これは常に問題の原因ですが、言語はこのように定義されています。今日、他の方法でそれを行う方法はありません。大量のコードが書かれており、これらの大量のコードはまさにこれを期待しています。

最初に、コピー後にこの配列をどうするかを決める必要があります。両方のオブジェクトco-ownがソース オブジェクトの配列である必要があり、この配列がこの時点で複製されている必要があります。これを決定したら、割り当て/コピー コンストラクターでこの戦略を実装する必要があります。

于 2013-10-26T07:02:28.870 に答える