' P '

whatever I will forget

C++ Deep Copying with copy constructor

Deep Copying / Shallow Copying があるようです。 Shallow copyでCopy Constructorを使用した場合、ポインタを用いているとメモリ破壊が起こることがあります。 要は、Deep Copyingだとcopyされた変数のアドレスを別に保持します!

class Shallow {
private:
    int *data;
public:
    void set_value(int d) { *data = d; }
    int get_value() { return *data; }
    Shallow(int a);
    Shallow(const Shallow &source);
    void display (Shallow s);
}

//constructor
Shallow::Shallow(int a) {
     data = new int;
     *data = a;
}

//Copy constructor 
Shallow::Shallow(const Shallow &source) 
     : data(source.data) {
}

//Destructor
Shallow::~Shallow() {
    delete data;
}

//method
void display_shallow(Shallow s) {
    cout << s.get_value() << endl;
}

int main() {

    //ob1を生成、Constructorが呼ばれて*data は100となる
    Shallow ob1{100};

    //ob1を使ってmethodをcall. Shallow sオブジェクトがcopy constructorを使って呼び出される
    //ob1をmethodに渡しているため、オブジェクトsの*dataがポイントする先はob1.dataと同じ
    display_shallow(ob1);
    //methodが終了すると、destructorが呼ばれる
    //正確にはオブジェクトsが削除されるはずだが、同じメモリ領域をポイントしているであるob1が参照する先が削除されちゃいました(invalidメモリーを参照)
    
    //ob1を使ってob2を生成、初期化(もちろんdataは同じメモリ領域を持っています)
    Shallow ob2{ob1};
    //ob1のdataの値も1000に変わっちゃいます
    ob2.set_value(1000);

    return 0;
}

上記みたいなことがポインタが絡んでくると発生しちゃうわけです。(ポインタだっる)

というわけで、上記みたいなことがしたければ、Deep Copyをしようね、って話になるみたいなんですよ

//Copy constructor (deep)
Shallow::Shallow(const Shallow &source) {
    data = new int;
    *data = *source.data
}

または、delegating constructorの書き方

//Copy constructor (deep)
Shallow::Shallow(const Shallow &source)
    : Shallow{ *source.data} {
}

上記であれば、display_shallow methodがcallされ、 copy constructorが呼ばれた際にオブジェクトsが新しいメモリ領域を参照してdataの値をコピーします
そのため、methodの処理が終了しても、元々のob1のメモリ参照先までdeleteしません!
また、ob2をob1で初期化、生成してもob2は別のメモリ領域を参照して作られます。

最後に、

Copy Constructorを明示的に定義したほうがいいケース

  1. 値でオブジェクトをパラメータとして渡す場合
  2. 値でオブジェクトを返り値として戻す場合
  3. オブジェクトを違うオブジェクトで初期化、生成する場合

そして、

Copy Constructorに関するTips

  • クラスにポインタメンバーがいる場合
  • Copy Constructorはconst参照パラメータを使おう (const &reference)
  • STL クラスを使えば最初から実はCopy Constructorを用意してくれてるらしい
  • というかポインタをクラスメンバに追加しなくていいやん

以上!!!!