茂加部珈琲店

主にtech関連のメモ置き場です

virtualなデストラクタ

C++では、ポリモーフィズムを利用するために作成した基底クラスのデストラクタにはvirtualを付けることがあるようです.
virtualがないと、基底クラスのポインタで管理している場合は、基底クラスのデストラクタのみが呼ばれてしまうためです.
初心者は「そんなこと聞いてないよ」となりそうで、不親切だとは思いますが、様々な理由でこうなっているはずなので仕方ないでしょう.

以下のようなコードで確認してみましょう

#include <iostream>
#include <memory>

struct Base{
    Base(){
        std::cout << "  Base constructor" << std::endl;
    }
    ~Base(){
        std::cout << "  Base destructor" << std::endl;
    }
};

struct Child : public Base{
    Child(){
        std::cout << "  Child constructor" << std::endl;
    }
    ~Child(){
        std::cout << "  Child destructor" << std::endl;    
    }
};

int main(){
    {
    std::cout << "unique_ptr:" << std::endl;
    std::unique_ptr<Base> pBase = std::make_unique<Child>();
    }
    {
    std::cout << "shared_ptr" << std::endl;
    std::shared_ptr<Base> pBase = std::make_shared<Child>();
    }
    std::cout << "Raw pointer" << std::endl; 
    Base* pBaseRaw = new Child();
    delete(pBaseRaw);

    return 0;
} 

実行結果はこうなります

unique_ptr:
  Base constructor
  Child constructor
  Base destructor
shared_ptr
  Base constructor
  Child constructor
  Child destructor
  Base destructor
Raw pointer
  Base constructor
  Child constructor
  Base destructor

Rawポインタとunique_ptrでは、Childのデストラクタが呼ばれていないのが確認できます.
基底クラスのデストラクタにvirtualをつければ、全てChildのデストラクタを呼ぶようになります
また、shared_ptrはvirtualデストラクタがないにもかかわらず、Childのデストラクタが呼ばれているのも面白いですね.
これは、shared_ptrが作成時のクラスを利用してポインタを破棄してくれるからみたいです.
しかし、unique_ptrではやはりvirtualが必要となるので、あまり安心はできなさそうですね.