#5 デフォルト代入演算子とデフォルトコピーコンストラクタの振る舞い

Effective C++ の2章で,コピー代入演算子,コピーコンストラクタについて説明されてますが,そもそも自分でこの関数を書かないといけない時がどういう時かはっきりわかってませんでした(汗)
ちょっとググッて下記のページを見つけ,

yohshiy.blog.fc2.com

実験コードを書いたんですが,結論としては,,,

クラス内部でメモリの動的管理を指定なければデフォルトでうまく動く!たとえ配列がメンバにあっても,静的に決まっていればOK!

ということがわかりました.何をもって”うまく動く”とするかは用途によって変わると思うんですが,今回のケースでは「コピー先にコピー元の内容が完全にコピーされて,別物になる.(変に同じメモリをさして共有されたりしない)」を”うまく動く”としました.デフォルトのコピー動作では配列はダメ(=ポインタだけがコピーされて,同じメモリをさしてしまう)なのかなと思ってたんですが,大丈夫でした.以下,サンプルコードです.ちなみに,vector とかのクラスをメンバとして持っている場合,クラスメンバの振る舞いはそのクラスの実装に依存します.

ポインタ変数をメンバに持つ場合,下記の2つのパターンがあると思うんですが,どちらの振る舞いにするか考えないと行けないですね.
1.ポインタの指し示すもの(同じもの)をコピー先とコピー元で共有する.
2.ポインタの指し示すものを,新たにメモリを確保して完全にコピーして,コピー先とコピー元で別物として保持する.


#include <iostream>

class ParentContainer {
public:
  virtual ~ParentContainer() {};

  enum {ARR_NUM = 3};
};

class ContainerDymanic : public ParentContainer{
public:
  ContainerDymanic() {
    arr = new int[ARR_NUM];
  }

  void print() {
    std::cout << "" << std::endl;
    for (int i = 0; i < ARR_NUM; i++) {
      std::cout << "cont[" << i << "]" << this->arr[i] << std::endl;
    }
  }

  void modifyArr(int val) {
    for (int i = 0; i < ARR_NUM; i++) {
      this->arr[i] = val;
    }
  }

  int *arr;
};

class ContainerStatic : public ParentContainer {
public:

  void print() {
    std::cout << "" << std::endl;
    for (int i = 0; i < ARR_NUM; i++) {
      std::cout << "cont[" << i << "]" << this->arr[i] << std::endl;
    }
  }

  void modifyArr(int val) {
    for (int i = 0; i < ARR_NUM; i++) {
      this->arr[i] = val;
    }
  }

  int arr[ARR_NUM];
};

int main(int, char**) {

  {
    ContainerStatic stContA, stContB;
    std::cout << "Default = operator for class without pointer member." << std::endl;
    stContA.modifyArr(100); 
    stContB = stContA;
    stContA.print();
    stContB.print();

    stContB.modifyArr(500);
    stContA.print();
    stContB.print();
  }

  {
    ContainerDymanic dynContA, dynContB; 
    std::cout << "" << std::endl;
    std::cout << "Default = operator for class with pointer member." << std::endl;
    dynContA.modifyArr(100);
    dynContB = dynContA;
    dynContA.print();
    dynContB.print();
    
    dynContB.modifyArr(500);
    dynContA.print();
    dynContB.print();
  }

    {
    ContainerStatic stContA;
    std::cout << "Default copy operator for class without pointer member." << std::endl;
    stContA.modifyArr(100); 
    ContainerStatic stContB(stContA);
    stContA.print();
    stContB.print();

    stContB.modifyArr(500);
    stContA.print();
    stContB.print();
  }

  {
    ContainerDymanic dynContA; 
    std::cout << "" << std::endl;
    std::cout << "Default copy operator for class with pointer member." << std::endl;
    dynContA.modifyArr(100);
    ContainerDymanic dynContB(dynContA);
    dynContA.print();
    dynContB.print();
    
    dynContB.modifyArr(500);
    dynContA.print();
    dynContB.print();
  }

  return 0;
}