M5Stack C++学習 クラスインスタンスをコピー

# クラスインスタンスをコピーする。
:::note
**＜確認したい内容＞**
**１．クラスインスタンスをコピーする場合、新たに領域を確保してコピーしているのか, 確認する。**

**２．代入演算子＝のオーバーロードで、きちんとコピーできるか。**

**３．コピーコンストラクタが起動する場合と、代入演算子＝が使用される場合、その用途の違いを確かめる。**

そもそも、**コピーという言葉があいまい**で、どう具体的にコピーされているのか、実コードで確認する。
:::

:::note
**C＋＋のコピー**には、2種類の定義があります。
**ディープコピーDeep Copy:**　実体を、新たな領域を確保してコピー。
**シャローコピーShallow Copy:**  ポインタ同士の、コピー。
:::

:::note
**コピーコンストラクタ構文**
```CPP:constructor.cpp
class　class_A
{
    public:
        class_A(const class_A& existedOtherClass);
};
```
定義は決まっているので、引数に同じクラスを割り当てると起動します。
:::

:::note 
**事前定義識別子　`__PRETTY_FUNCTION__ `** 
名前空間名、クラス名、戻り値やパラメータといった情報も含む関数の文字列。
**デバッグなどで、実行された関数名を表示したいときに使用します。**
:::

:::note warn
クラスインスタンスのコピーを行うときは、メンバー変数に外部本体をもつポインターがあるか、確認しておきます。
コピーしたときに、ポインタが保持しているアドレスはコピーされますが、２つのクラスインスタンスが、一つの実態しかないオブジェクトを、不意に共有してしまう可能性があります。デストラクタの、２重解放もありえます。
**コンパイラの自動生成したコピーコンストラクタを使うときは、注意が必要です。**
:::


# クラスインスタンスのコピー　動作確認コード
`__PRETTY__FUNCTION__`を使用して、どのメソッドが、どの順番で、起動したか、
確認できるようにしています。

**１．CLクラスインスタンス`CL1`の生成**

**２．CLクラスインスタンス`CL2`を`CL1`のコピーコンストラクタで生成。**
　　※`CL1`と`CL2`のアドレスが違うことを確認。

**３．`CL2`のメンバー変数を変更し、`CL1`に変化がないことを確認。**

**４．CLクラスインスタンス`CL3`を代入演算子＝を使用して、コピーコンストラクタで生成。**
　　※このとき、代入演算子＝のオーバーロードで生成されていないことを確認。

**５．CLクラスインスタンス`CL4`をCLクラスコンストラクタで生成。**

**６．代入演算子＝をつかって`CL4`に`CL1`を代入。コピーされているか確認。**
　　※このとき、代入演算子＝のオーバーロードが使用されているか、確認。

**７．setupを抜けると各インスタンスのデストラクタが起動。その順番を確認。**

```CPP:main.cpp
#include <M5Core2.h>

/**
 * コピーコンストラクタ
 * ディープコピー
 * 事前定義識別子
*/

class CL
{
  public:
    //コンストラクタ
    CL(String s, int n)
    { Serial.printf("%s\r",__PRETTY_FUNCTION__);  name=s; num=n; }
    //デストラクタ
    ~CL(){Serial.printf("%s %x\r ",__PRETTY_FUNCTION__, this);}
    //コピーコンストラクタ
    CL(const CL& _cl)
    { Serial.printf("%s\r",__PRETTY_FUNCTION__); num=_cl.num; name=_cl.name;}
    //代入演算子＝オーバーロード
    CL& operator=(const CL& _cl)
    { Serial.printf("%s\n",__PRETTY_FUNCTION__); num=_cl.num; name=_cl.name; return *this;};
    //メンバ変数の表示
    void print(String s){Serial.printf("%s Add:%x name:%s,num:%d\r", s, this, name, num);}
  public:
    String name;
    int num;    
};

void setup()
{
    M5.begin();
    Serial.print("------CL1 Construction-------\r");
    CL CL1("CL1",1);
    CL1.print("CL1");
    Serial.print("------CL2 Copy Construction-------\r");
    CL CL2(CL1);
    CL1.print("CL1");
    CL2.print("CL2");
    Serial.print("------Change CL2 values-------\r");
    CL2.name="CL2";
    CL2.num=2;
    CL1.print("CL1");
    CL2.print("CL2");
    Serial.print("------Initial Copy CL3=CL1 ----------\r");
    CL CL3 = CL1;
    CL1.print("CL1");
    CL2.print("CL2");
    CL3.print("CL3");
    Serial.print("------CL4 Construction ----------\r");
    CL CL4("CL4",4);
    CL4.print("CL4");
    Serial.print("------CL4 = CL1 ----------\r");
    CL4 = CL1;
    CL1.print("CL1");
    CL4.print("CL4");
    Serial.print("------Close destruction ----------\r");
}

void loop()
{
   delay(1);
}

```
**シリアルに出力した、実行結果**
![コピーコンストラクタ結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/ccc9fdab-0a3d-d2a6-8bb5-5c8b68f80622.png)

今回は、ディープコピーで、実体を２つに増やすことをメインに検証しました。
インスタンスコピーに関して、理解の解像度が上がったと思います。

# ＜参照サイト＞

https://cpprefjp.github.io/lang/cpp11/func.html

https://rinatz.github.io/cpp-book/ch06-03-deep-and-shallow-copy/

https://qiita.com/AAsada/items/40eee182e868c40f7cd7