C++
 Computer >> コンピューター >  >> プログラミング >> C++

【C++】コピーコンストラクタと代入演算子の違いを徹底解説

C++には、あるオブジェクトをもとに別のオブジェクトを初期化・設定するための仕組みとして、「コピーコンストラクタ」と「代入演算子」の2つがあります。一見似ていますが、両者には重要な違いがあります。

最大の違いはメモリの扱いです。コピーコンストラクタは、新しいオブジェクトに対して独立したメモリ領域を新たに作成します。一方、代入演算子は新しいメモリ領域を確保せず、すでに存在するオブジェクト同士の間で値を受け渡すだけです。

コピーコンストラクタとは

コピーコンストラクタは、同じクラスの既存オブジェクトをもとに新しいオブジェクトを初期化するための特殊なコンストラクタです。実体としては、引数に自分自身のクラス型へのconst参照を取る「オーバーロードされたコンストラクタ」です。コピー元とコピー先はそれぞれ別のメモリ領域を持つため、片方の変更がもう片方に影響することはありません。

コピーコンストラクタの構文

classname (const classname &obj) {
   // コンストラクタの本体
}

代入演算子とは

代入演算子(=)は、すでに存在する2つのオブジェクトの間で、一方の値をもう一方に割り当てるために使われる演算子です。新しいメモリ領域は確保されず、既存のオブジェクトの内容が上書きされます。デフォルトではビット単位のコピー(浅いコピー)が行われるため、動的メモリを扱うクラスでは適切にオーバーロードすることが推奨されます。

代入演算子の構文

classname Ob1, Ob2;
Ob2 = Ob1;

コピーコンストラクタと代入演算子の違い一覧

コピーコンストラクタ代入演算子
基本的に「オーバーロードされたコンストラクタ」である基本的に「演算子」である
既存のオブジェクトを使って、新しいオブジェクトを初期化するすでに存在する2つのオブジェクト間で、一方の値を他方に代入する
既存のオブジェクトをもとに新しいオブジェクトを生成するときに使用される既存のオブジェクトに別の既存オブジェクトの値を割り当てたいときに使用される
両方のオブジェクトは、それぞれ独立したメモリ領域を持つ新しいメモリ領域は確保されず、既存のオブジェクトの内容が更新される
クラス内で定義されていない場合、コンパイラが自動的に提供するオーバーロードされていない場合、ビット単位のコピーが行われる

動作の違いがわかるサンプルコード

次の例では、オブジェクトの生成時にコピーコンストラクタが、既存オブジェクトへの代入時に代入演算子が、それぞれ呼び出される様子を確認できます。

#include 
using namespace std;

class Sample {
    int value;
public:
    Sample(int v) : value(v) {}

    // コピーコンストラクタ
    Sample(const Sample &obj) : value(obj.value) {
        cout << "コピーコンストラクタが呼ばれました" << endl;
    }

    // 代入演算子
    Sample& operator=(const Sample &obj) {
        if (this != &obj) {
            value = obj.value;
        }
        cout << "代入演算子が呼ばれました" << endl;
        return *this;
    }
};

int main() {
    Sample a(10);
    Sample b = a;   // 新規オブジェクトの生成 → コピーコンストラクタ
    Sample c(0);
    c = a;          // 既存オブジェクトへの代入 → 代入演算子
    return 0;
}

使い分けのポイント

  • オブジェクトの宣言と同時に初期化する場合Sample b = a; など)→ コピーコンストラクタが呼ばれる
  • 宣言済みのオブジェクトに後から値を設定する場合c = a; など)→ 代入演算子が呼ばれる
  • ポインタや動的メモリをメンバに持つクラスでは、浅いコピーによる二重解放などの問題を避けるため、両者を適切に自前で定義することが重要です。
  1. C++におけるドット演算子(.)とアロー演算子(->)の違いを徹底解説

    C++では、ドット演算子(.)とアロー演算子(->)はどちらもクラスのメンバーにアクセスするために使用されますが、それぞれ使用される場面が異なります。C++において、class、struct、unionとして宣言された型はすべて「クラスタイプ」とみなされるため、以下の説明はこれら3つすべてに当てはまります。基本的な使い分けa.b は、b がオブジェクト a(またはオブジェクトへの参照[1])のメンバーである場合にのみ使用できます。つまり、a.b の形式では、a は常にクラスの実際のオブジェクト(またはその参照)でなければなりません。a->b は、本質的に (*a).b の省略記法で

  2. Pythonの「=」と「==」の違いとは?代入と比較の使い分けを徹底解説

    Pythonにおける「=」と「==」の基本的な違いPythonでは「=」と「==」はまったく異なる役割を持つ記号です。初心者が混同しやすいポイントですが、それぞれの意味を正しく理解しておくことが重要です。「=」は代入演算子Pythonにおいて「=」記号は代入演算子として定義されています。左辺には1つの変数を、右辺には式を置く必要があり、右辺の式が評価された結果の値が、左辺の変数に格納されます。つまり、式と変数名は入れ替えて使うことはできません。>>> a=10 >>> b=20 >>> c=a+b >>> a,b,c (1