デストラクタの多重呼び出しによるポインタの多重解放をスマートポインタで突破する

# デストラクタの多重呼び出しによるエラー
調べていると自分と似たような状況にあった質問を発見。
ポインタを多重で解放していたのが問題みたい

https://stackoverflow.com/questions/55368498/c-why-emplacing-object-in-vector-segfaults

基本的には上記の改変です。

```test.cpp
#include <iostream>
#include <vector>

using namespace std;

class IBehavior
{
public:
    IBehavior() = default;
    virtual ~IBehavior() = default;
    virtual void execute() = 0;
};

class Drink : public IBehavior
{
public:
    Drink(): IBehavior() {}
    ~Drink() {}
    void execute() { cout << "Drinking" << endl; }
};

class Eat : public IBehavior
{
public:
    Eat(): IBehavior() {}
    ~Eat() {}
    void execute() { cout << "Eating" << endl; }
};


class Act
{
    IBehavior * b;

public:

    enum class BehaviorType { eat = 0, drink = 1 };

    Act() = default;
    ~Act()
    {
        cout << "Calling the destructor" << endl;
        delete b;
    }
    Act(BehaviorType b_type) { SetBehavior(b_type); }

    Act(Act&& act)
    {
        cout << "Calling the move constructor" << endl;
        this->b = act.b;
    }


    void SetBehavior(BehaviorType b_type)
    {
        if(b_type == BehaviorType::eat) b = new Eat();
        if(b_type == BehaviorType::drink) b = new Drink();
    }

    void execute() { b->execute(); }
};


int main(int argc, char * argv[])
{
    vector<Act> action_vector;

    for(int i = 0; i < 10; ++i)
    {
        action_vector.emplace_back(Act::BehaviorType::eat);
        action_vector[i].execute();
    }

    return 0;
}

```
これを実行すると。。。

```./a.out
Eating
Calling the move constructor
Calling the destructor
Eating
Calling the move constructor
Calling the move constructor
Calling the destructor
Calling the destructor
zsh: segmentation fault  ./a.out
```

このようにデストラクタが多重呼び出しされてしまう。これによって存在しないポインタを削除しようとしてエラーが生じる


```
Act(Act&& act)
    {
        cout << "Calling the move constructor" << endl;
        this->b = act.b; // コピー
    }
```

ここでact.bをthis->bにコピーした後に削除していないために2度呼び出されている。

# 解決策
## 1. ```act.b```にnullポインタを割り当てる
以下のサイトにあるようにnullポインタを削除する分には問題がないみたいです。

https://kaworu.jpn.org/cpp/C++はヌルポインタをdeleteしても問題ない

```diff_cpp
Act(Act&& act)
    {
        cout << "Calling the move constructor" << endl;
        this->b = act.b;
+       act.b = nullptr; // <= ヌルポインタ

    }
```


## 2.  ```unique_ptr```を使う
ユニークポインタというものがあるらしいです。

>unique_ptr<T>は、あるメモリに対する所有権を持つポインタが、ただ一つであることを保証するようなスマートポインタである。 auto_ptr<T>同様に、テンプレート引数で保持するポインタ型を指定し、スマートポインタが破棄される際にディストラクタにおいて自動的にメモリを解放する。
https://qiita.com/hmito/items/db3b14917120b285112f

自動的に解放するため自分でdeleteを書く必要がありません。そのため、デストラクタが2回呼び出されても削除が行われません。

```diff_cpp
class Act
{
-   IBehavior * b;
+   unique_ptr<IBehavior> b; // unique_ptr

public:

    enum class BehaviorType { eat = 0, drink = 1 };

    Act() = default;
    ~Act()
    {
        cout << "Calling the destructor" << endl;
-       delete b; // deleteは自動的に行われる
    }
    Act(BehaviorType b_type) { SetBehavior(b_type); }

    Act(Act&& act)
    {
        cout << "Calling the move constructor" << endl;
-       this->b = act.b;
+       this->b = move(act.b); // unique_ptrは代入は出来ないが移動はできる
    }


    void SetBehavior(BehaviorType b_type)
    {
-       if(b_type == BehaviorType::eat) b = new Eat();
+       if(b_type == BehaviorType::eat) b.reset(new Eat()); // リセットで明示的に値を変更
-       if(b_type == BehaviorType::drink) b = new Drink();
+       if(b_type == BehaviorType::drink) b.reset(new Drink());
    }

    void execute() { b->execute(); }
};


int main(int argc, char * argv[])
{
    vector<Act> action_vector;

    for(int i = 0; i < 10; ++i)
    {
        action_vector.emplace_back(Act::BehaviorType::eat);
        action_vector[i].execute();
    }

    return 0;
}


```

unique_ptr非常に便利だと感じました。自分がぶつかった似た問題も無事に解決し、これから学んでいこうと思います。