1. ホーム
  2. c++

[解決済み] GNU GCC (g++)。なぜ複数のdtorが生成されるのですか?

2023-02-26 03:10:25

質問

開発環境は?GNU GCC (g++) 4.1.2

単体テストで「コードカバレッジ(特に関数カバレッジ)」を高める方法を調べているうちに、クラスdtorの一部が複数回生成されているようなことがわかりました。この原因についてご存知の方はいらっしゃいますか?

上記の内容を以下のコードで試して観察してみました。

"test.h"にあります。

class BaseClass
{
public:
    ~BaseClass();
    void someMethod();
};

class DerivedClass : public BaseClass
{
public:
    virtual ~DerivedClass();
    virtual void someMethod();
};

"test.cpp"にあります。

#include <iostream>
#include "test.h"

BaseClass::~BaseClass()
{
    std::cout << "BaseClass dtor invoked" << std::endl;
}

void BaseClass::someMethod()
{
    std::cout << "Base class method" << std::endl;
}

DerivedClass::~DerivedClass()
{
    std::cout << "DerivedClass dtor invoked" << std::endl;
}

void DerivedClass::someMethod()
{
    std::cout << "Derived class method" << std::endl;
}

int main()
{
    BaseClass* b_ptr = new BaseClass;
    b_ptr->someMethod();
    delete b_ptr;
}

上記のコードをビルド(g++ test.cpp -o test)して、どのようなシンボルが生成されたかを確認すると、以下のようになります。

nm --demangle test

以下のような出力が確認できました。

==== following is partial output ====
08048816 T DerivedClass::someMethod()
08048922 T DerivedClass::~DerivedClass()
080489aa T DerivedClass::~DerivedClass()
08048a32 T DerivedClass::~DerivedClass()
08048842 T BaseClass::someMethod()
0804886e T BaseClass::~BaseClass()
080488f6 T BaseClass::~BaseClass()

私の質問は以下の通りです。

1) なぜ複数のdtorが生成されたのですか(BaseClass - 2, DerivedClass - 3)?

2) それぞれのdtorは何が違うのですか?複数のdtorをどのように使い分けるのでしょうか?

C++プロジェクトで100%の関数カバレッジを達成するためには、私のユニットテストでこれらのdtorをすべて呼び出すことができるように、これを理解する必要があるという気がしてきました。

どなたか、上記についてご回答いただけると幸いです。

どのように解決するのですか?

まず、これらの機能の目的については Itanium C++ ABI の下の定義を参照してください。マングル化された名前へのマッピングは5.1.4で示されています。

基本的には

  • D2 はベースオブジェクトのデストラクタです。これは、データメンバや非仮想ベースクラスと同様に、オブジェクト自体を破壊します。
  • D1 は "完全なオブジェクトのデストラクタです。これはさらに仮想基底クラスを破壊します。
  • D0 は、削除オブジェクトのデストラクタです。これは完全なオブジェクトのデストラクタが行うすべてのことを行い、さらに operator delete を呼び出して実際にメモリを解放します。

仮想基底クラスがない場合、D2とD1は同一です。GCCは、十分な最適化レベルにおいて、実際にシンボルを両方とも同じコードにエイリアスします。