2

私はC ++の初心者です。とにかく解決できない問題があります。より良いクラスとオーバーロード演算子を理解するためのコードを書きました:

#include <iostream>
#include <stdlib.h>
#include <stdarg.h>
using namespace std;

class vectmy {
public:
    int size;   
int *a;
vectmy(int n,int val);
~vectmy (){delete[] a;   //IF I DELETE THIS PROGRAM WORKS
}
vectmy & operator = (const vectmy &);
};

 vectmy::vectmy(int n,int val){
    size=n;
    a = new int[ n+1 ];
    for (int i=0;i<n;++i){
    *(a+i)=val;
    }
 }



   vectmy& vectmy::operator= (const vectmy& param)
  {
   for (int i=0;i<3;++i)    a[i]=param.a[i];
    return *this;
   }



 vectmy operator+( vectmy left, vectmy right)
  {
  vectmy result = left;
  for (int i=0;i<3;++i) result.a[i]=result.a[i]+right.a[i];

  return result;
   }



int main() {
int b1[3]={1,2,4};
vectmy d(3,2),b(3,4),c(3,0);

c=(b+d);

for (int j=0; j<3; ++j)cout<<c.a[j]<<' '<<endl; 
return 0;
}

実行するとクラッシュします。デストラクタを削除すると動作します。なぜそれが起こるのですか?

4

2 に答える 2

4

実行するとクラッシュします。デストラクタを削除すると動作します。なぜそれが起こるのですか?

あなたはここのコピーoperator +作成します:left

vectmy result = left;

コピー コンストラクターを明示的に定義していないため、コンパイラは、メンバーごとのコピーを実行するコンストラクターを暗黙的に生成します。

aデータ メンバーの鈍いコピーは、aポインタが最終的に(と)の 2 つの異なるインスタンスの同じ場所を指すことを意味し、どちらも破棄時にそうなります。vectmyresultleftdelete[]

このような二重削除は、プログラムにundefined behaviorを与えます。これは、あなたの場合、クラッシュとして現れます。

これが 3 つのルールのポイントです。ユーザー定義のコピー コンストラクター、代入演算子、またはデストラクターがある場合は常に、それらすべてを定義する必要があります。

その理由は、通常、リソース (この場合はメモリ) を管理しているため、これらの関数のいずれかを定義し、リソースを管理するオブジェクトをコピー、破棄、または割り当てるときに適切なアクションを実行する必要があるためです。

この特定のケースでは、適切なコピー コンストラクターがありません。これはあなたがそれを定義する方法です:

vectmy::vectmy(vectmy const& v)
{
    size=v.size;
    a = new int[size];
    *this = v;
}

また、可能な限り、生のポインター、、newおよびdelete(または対応する配列)による手動のメモリ管理を避け、std::vector代わりに使用することを検討することをお勧めします。

アップデート:

また、 your がそのパラメーターを valueoperator +で受け取っていることにも注意してください。つまり、各引数がコピーされます (つまり、コピー コンストラクターが呼び出されます)。

ここではコピーは実際には必要ないため、参照によってパラメーターを取得することができます (へconst):

vectmy operator + ( vectmy const& left, vectmy const& right)
//                         ^^^^^^              ^^^^^^
于 2013-04-20T11:30:54.667 に答える
1

あなたの中operator+

vectmy result = left;

これにより、デフォルトのコンストラクターとコピーコンストラクターが呼び出されますが、それらはありません。aそのため、メンバーにメモリを割り当てないコンパイラのバリアントが使用されます。自動生成されたコピー コンストラクターの場合、ポインターは単純にコピーされ、2 つのオブジェクトが同じポインターを使用します。一方が削除されると、もう一方のポインタは無効になります。

3 のルールについて読む必要があります。

于 2013-04-20T11:30:06.123 に答える