GNU GCC (g++):为什么它生成多个博士
GNU GCC (g++): Why does it generate multiple dtors?
开发环境:GNU GCC (g++) 4.1.2
当我试图研究如何在单元测试中增加"代码覆盖率——特别是功能覆盖率"时,我发现一些类博士似乎被生成了多次。你们中有人知道为什么吗?
我试着用下面的代码观察我上面提到的。
在"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试验
我可以看到如下输出:
==== 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)为什么生成了多个医生(BaseClass - 2, DerivedClass - 3)?
2)这些医生有什么不同?如何有选择地使用这些医生?
我现在有一种感觉,为了在c++项目中实现100%的功能覆盖率,我们需要理解这一点,以便我可以在单元测试中调用所有这些医生。
如果有人能给我上述问题的答复,我将非常感激。
首先,在Itanium c++ ABI中描述了这些函数的用途;参见"基对象析构函数"、"完全对象析构函数"answers"删除析构函数"中的定义。到变形名称的映射在5.1.4中给出。
基本上:
- D2是"基对象析构函数"。它会销毁对象本身,以及数据成员和非虚基类。
- D1是"完全对象析构函数"。它还会销毁虚拟基类。
- D0是"删除对象析构函数"。它做所有的对象析构函数做的事情,加上它调用
operator delete
来释放内存。
如果没有虚基类,D2和D1是相同的;在足够的优化级别上,GCC实际上会将两个符号别名为相同的代码。
通常有两个构造函数(not-in-charge/in-charge)和三个析构函数(not-in-charge/in-charge/in-charge deleting)。
not-in-charge ctor和dtor在处理使用virtual
关键字从另一个类继承的类的对象时使用,当该对象不是完整的对象(因此当前对象"不负责"构造或析构虚拟基对象)。这个函数接收一个指向虚基对象的指针并存储它。
负责 actor和doctors用于所有其他情况,即如果不涉及虚拟继承;如果类有虚析构函数,则负责删除 dtor指针将进入虚值表槽,而知道对象动态类型的作用域(即具有自动或静态存储时间的对象)将使用负责的 dtor(因为该内存不应该被释放)。
代码示例:
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);
结果:
-
foo
,baz
和quux
的每个变量中的dr表项指向各自的负责删除 dr。 -
b1
和b2
由baz()
in-charge构造,调用foo(1)
in-charge -
q1
和q2
是由quux()
in-charge构造的,foo(2)
in-charge和baz()
not- charge有一个指针指向之前构造的foo
对象 -
q2
被~auto_ptr()
in-charge销毁,~quux()
in-charge删除虚拟医生,~baz()
not-in-charge、~foo()
in-charge和operator delete
调用。q1
被~quux()
in-charge销毁,~baz()
not-in-charge和~foo()
in-charge -
b2
被~auto_ptr()
in-charge销毁,它调用虚拟医生~baz()
in-charge删除,~foo()
in-charge和operator delete
b1
被~baz()
in-charge销毁,它调用~foo()
in-charge任何从quux
派生的人都将使用它的不负责的 tor和tor,并承担创建foo
对象的责任。
原则上,没有虚基的类永远不需要不负责的变体;在这种情况下,负责的变体有时被称为统一的,并且/或者负责的和不负责的的符号被别名为单个实现。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么比较运算符如此快速
- 为什么 Serial.println(<char[]>);返回随机字符?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 为什么不;名字在地图上是按顺序排列的吗
- 我的字符计数代码计算错误.为什么
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 为什么 std::unique 不调用 std::sort?
- 既然存在危险,为什么项目要使用-I include开关
- GNU GCC (g++):为什么它生成多个博士