これを見てみましょう。
名前からわかるように、それはコンストラクターです。同じ型のオブジェクトへの参照をパラメーターとして受け取るため、コピーコンストラクター(C ++の命名法)です。
ご存知のように(またはそうでない場合)、コピーコンストラクターがない場合は、コンパイラーがコピーコンストラクターを生成します。コンパイラによって生成されたコピーコンストラクタは、浅いコピーを実行します。
独自に実装する理由:
class Car {
char *LicencePlate;
public:
Car(char* plate, int size)
{
LicencePlate = new char[size];
strcpy(LicencePlate, plate);
}
~Car()
{
delete[] LicencePlate;
}
};
説明をわかりやすくするために、クラスを少し変更しました。あなたのクラスは今メモリを管理しています。にメモリを割り当てますLicencePlate
。これは、コピーコンストラクターがないシナリオです。あなたがするように言う:
Car a("abc",3);
コンパイラによって生成されたコピーコンストラクタは、次のように呼び出されます。
Car b(a);
ただし、これは浅いコピーのみを行うことを忘れないでください。だから、実際には、a.LicencePlate == b.LicencePlate
。何か問題がありますか?
スコープ外にa
なると、デストラクタが呼び出さa.LicencePlate
れて削除されます。b
ただし、スコープ外になると、デストラクタが同じメモリを削除しようとするため、未定義の動作が発生しb
ます(浅いコピーが作成されたため、2つのポインタが同じメモリを指していることに注意してください)。
これを回避するには、独自のコピーコンストラクターを定義します。
class Car {
char *LicencePlate;
int sz;
public:
Car(char* plate, int size)
{
LicencePlate = new char[size+1]();
strcpy(LicencePlate, plate);
sz = size;
}
Car(const Car& other)
{
LicencePlate = new char[other.sz+1]();
sz = other.sz;
strcpy(LicencePlate, other.LicencePlate);
}
~Car()
{
delete[] LicencePlate;
}
};
三つのルールは、代入演算子を実装する必要があることを意味します(すでにコピーコンストラクタとデストラクタがあります)。この背後にある動機は同じですが、初期化する代わりに割り当てるときに問題が再現されるだけです。
Car a("abc",3);
Car b;
b = a; //assignment - operator= is called
今、私たちは安全です。b
、コピーすると、ナンバープレートを保持するために新しいメモリが割り当てられるため、二重削除は発生しません。
ポイントを示すためにコードを変更しましたが、それでも自分でロジックを配置する必要があります。