简体   繁体   English

GNU GCC (g++):为什么会生成多个 dtor?

[英]GNU GCC (g++): Why does it generate multiple dtors?

Developing environment: GNU GCC (g++) 4.1.2开发环境:GNU GCC (g++) 4.1.2

While I'm trying to investigate how to increase 'code coverage - particularly function coverage' in unit testing, I've found that some of class dtor seems to be generated multiple times.虽然我正在尝试研究如何在单元测试中增加“代码覆盖率 - 特别是 function 覆盖率”,但我发现一些 class dtor 似乎被生成了多次。 Does some of you have any idea on why, please?请问你们中的一些人知道为什么吗?

I tried and observed what I mentioned the above by using the following code.我使用以下代码尝试并观察了上面提到的内容。

In "test.h"在“test.h”中

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

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

In "test.cpp"在“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;
}

When I built the above code (g++ test.cpp -o test) and then see what kind of symbols have been generated as follows,当我构建上面的代码(g++ test.cpp -o test)然后看看生成了什么样的符号如下,

nm --demangle test nm --demangle 测试

I could see the following output.我可以看到以下 output。

==== 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()

My questions are as follows.我的问题如下。

1) Why multiple dtors have been generated (BaseClass - 2, DerivedClass - 3)? 1)为什么生成了多个dtor(BaseClass - 2,DerivedClass - 3)?

2) What are the difference among these dtors? 2)这些dtors有什么区别? How those multiple dtors will be selectively used?如何有选择地使用这些多个 dtor?

I now have a feeling that in order to achieve 100% function coverage for C++ project, we would need to understand this so that I can invoke all those dtors in my unit tests.我现在有一种感觉,为了在 C++ 项目中实现 100% 的 function 覆盖率,我们需要了解这一点,以便我可以在单元测试中调用所有这些 dtor。

I would greately appreciate if someone could give me the reply on the above.如果有人能给我上面的答复,我将不胜感激。

First, the purposes of these functions are described in the Itanium C++ ABI ;首先, Itanium C++ ABI中描述了这些函数的用途; see definitions under "base object destructor", "complete object destructor", and "deleting destructor".请参阅“基本 object 析构函数”、“完整 object 析构函数”和“删除析构函数”下的定义。 The mapping to mangled names is given in 5.1.4. 5.1.4 中给出了到重整名称的映射。

Basically:基本上:

  • D2 is the "base object destructor". D2 是“基础 object 析构函数”。 It destroys the object itself, as well as data members and non-virtual base classes.它会破坏 object 本身,以及数据成员和非虚拟基类。
  • D1 is the "complete object destructor". D1 是“完整的 object 析构函数”。 It additionally destroys virtual base classes.它还破坏了虚拟基类。
  • D0 is the "deleting object destructor". D0 是“删除 object 析构函数”。 It does everything the complete object destructor does, plus it calls operator delete to actually free the memory.它完成了完整的 object 析构函数所做的所有事情,而且它调用operator delete来实际释放 memory。

If you have no virtual base classes, D2 and D1 are identical;如果您没有虚拟基类,则 D2 和 D1 是相同的; GCC will, on sufficient optimization levels, actually alias the symbols to the same code for both. GCC 将在足够的优化级别上,实际上将符号别名为两者的相同代码。

There are usually two variants of the constructor ( not-in-charge / in-charge ) and three of the destructor ( not-in-charge / in-charge / in-charge deleting ).通常有两种构造函数( not-in-charge / in-charge )和三种析构函数( not-in-charge / in-charge / in-charge delete )。

The not-in-charge ctor and dtor are used when handling an object of a class that inherits from another class using the virtual keyword, when the object is not the complete object (so the current object is "not in charge" of constructing or destructing the virtual base object). The not-in-charge ctor and dtor are used when handling an object of a class that inherits from another class using the virtual keyword, when the object is not the complete object (so the current object is "not in charge" of constructing or破坏虚拟基础对象)。 This ctor receives a pointer to the virtual base object and stores it.这个ctor接收一个指向虚拟基础object的指针并存储它。

The in-charge ctor and dtors are for all the other cases, ie if there is no virtual inheritance involved;负责人和dtors适用于所有其他情况,即如果没有涉及虚拟inheritance; if the class has a virtual destructor, the in-charge deleting dtor pointer goes into the vtable slot, while a scope that knows the dynamic type of the object (ie for objects with automatic or static storage duration) will use the in-charge dtor (because this memory should not be freed). if the class has a virtual destructor, the in-charge deleting dtor pointer goes into the vtable slot, while a scope that knows the dynamic type of the object (ie for objects with automatic or static storage duration) will use the in-charge dtor (因为不应释放此 memory)。

Code example:代码示例:

struct foo {
    foo(int);
    virtual ~foo(void);
    int bar;
};

struct baz : virtual foo {
    baz(void);
    virtual ~baz(void);
};

struct quux : baz {
    quux(void);
    virtual ~quux(void);
};

foo::foo(int i) { bar = i; }
foo::~foo(void) { return; }

baz::baz(void) : foo(1) { return; }
baz::~baz(void) { return; }

quux::quux(void) : foo(2), baz() { return; }
quux::~quux(void) { return; }

baz b1;
std::auto_ptr<foo> b2(new baz);
quux q1;
std::auto_ptr<foo> q2(new quux);

Results:结果:

  • The dtor entry in each of the vtables for foo , baz and quux point at the respective in-charge deleting dtor. foobazquux的每个 vtable 中的 dtor 条目指向相应的负责删除dtor。
  • b1 and b2 are constructed by baz() in-charge , which calls foo(1) in-charge b1b2baz() in-charge构造,它调用foo(1) in-charge
  • q1 and q2 are constructed by quux() in-charge , which falls foo(2) in-charge and baz() not-in-charge with a pointer to the foo object it constructed earlier q1q2quux() in-charge构造,它落在foo(2) in-chargebaz() not-in-charge 中,并带有指向它之前构造的foo object 的指针
  • q2 is destructed by ~auto_ptr() in-charge , which calls the virtual dtor ~quux() in-charge deleting , which calls ~baz() not-in-charge , ~foo() in-charge and operator delete . q2~auto_ptr() in-charge破坏,它调用虚拟 dtor ~quux() in-charge 删除,它调用~baz() not-in-charge~foo() in-chargeoperator delete
  • q1 is destructed by ~quux() in-charge , which calls ~baz() not-in-charge and ~foo() in-charge q1~quux() in-charge破坏,它调用~baz() not-in-charge~foo() in-charge
  • b2 is destructed by ~auto_ptr() in-charge , which calls the virtual dtor ~baz() in-charge deleting , which calls ~foo() in-charge and operator delete b2~auto_ptr() in-charge破坏,它调用虚拟 dtor ~baz() in-charge delete ,它调用~foo() in-chargeoperator delete
  • b1 is destructed by ~baz() in-charge , which calls ~foo() in-charge b1~baz() in-charge破坏,它调用~foo() in-charge

Anyone deriving from quux would use its not-in-charge ctor and dtor and take on the responsibility of creating the foo object.任何从quux派生的人都将使用其不负责的ctor 和 dtor 并负责创建foo object。

In principle, the not-in-charge variant is never needed for a class that has no virtual bases;原则上,没有虚拟碱基的 class 永远不需要非负责变体; in that case, the in-charge variant is then sometimes called unified , and/or the symbols for both in-charge and not-in-charge are aliased to a single implementation.在这种情况下,负责变体有时被称为统一,和/或负责负责的符号被别名为单个实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM