LoginSignup
0
0

More than 1 year has passed since last update.

【C++】基底クラスに virtual デストラクタを用意しないと、派生先のメンバクラスが解放されない

Last updated at Posted at 2023-01-06

C++ 初心者なのでかなりハマってしまった……。指摘等あればください、お願いします。
使用ツールは Visual Studio 2017 です。

注意
この記事の内容はあくまで推測なので、間違いの可能性があります

ご指摘いただきました
コメントに詳しい理由が書かれています。また、より実践的な例も指摘いただいております。

まとめ

  • ポリモーフィックに運用する基底クラスで、派生クラスがオブジェクトを保持する場合、基底クラスのデストラクタを virtual にする。
    → 派生先の保持するメンバクラスのデストラクタが呼ばれないため。

参考にさせて頂いたサイト

C++のメモリリーク検出!Visual Studio系
【c++】デストラクタにvirtualを付ける場合、付けない場合。

問題のコード

メモリリークするコードを提示します。

main.cpp
// メモリリーク検出用
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>

#include <string>

// 基底クラス
class Base {
};

// 派生クラス
class Derived : public Base {
private:
	std::string str;
};

int main() {
    // メモリリークを検出する
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);

	Base* polymorphic = new Derived;

	delete polymorphic;
}

上記のコードでは、派生クラスのstd::string strが解放されず、メモリリークします。

派生クラスではデストラクタを使用しないため、基底クラスには virtual デストラクタを実装していません。が、これはおそらく誤りです

コメントで指摘いただきました
この場合、どうやら未定義動作となるようです。詳しくはコメントをご覧ください。

修正方法

修正済みのコードを提示します。

main.cpp
// メモリリーク検出用
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>

#include <string>

// 基底クラス
class Base {
+ public:
+     virtual ~Base(){};
};

// 派生クラス
class Derived : public Base {
private:
	std::string str;
};

int main() {
    // メモリリークを検出する
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);

	Base* polymorphic = new Derived;

	delete polymorphic;
}

上記のコードでは、基底クラスに virtual なデストラクタを実装しています。これにより、メモリリークが発生しません。
「基底クラスに virtual なデストラクタを実装しないと、派生クラスのデストラクタが呼ばれない」
と覚えていたのがダメだった。どうやら、派生クラスの持つメンバクラスのデストラクタも呼ばれないようです。

コメントで指摘いただきました
問題のコードの場合、どうやら未定義動作となるようです。詳しくはコメントをご覧ください。

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0