C++ GNU GCC(g+;+;):为什么它会生成多个DTOR?

C++ GNU GCC(g+;+;):为什么它会生成多个DTOR?,c++,g++,destructor,C++,G++,Destructor,开发环境:GNUGCC(g++)4.1.2 当我试图研究如何在单元测试中增加“代码覆盖率——特别是函数覆盖率”时,我发现一些类dtor似乎被多次生成。请问你们当中有人知道为什么吗 我使用下面的代码尝试并观察了上面提到的内容 在“test.h”中 在“test.cpp”中 我的问题如下 1) 为什么生成了多个DTR(基类-2,派生类-3) 2) 这些DTR之间有什么区别?如何有选择地使用这些多个DTR 我现在感觉到,为了实现C++项目的100%个功能覆盖,我们需要理解这一点,这样我就可以调用我的单

开发环境:GNUGCC(g++)4.1.2

当我试图研究如何在单元测试中增加“代码覆盖率——特别是函数覆盖率”时,我发现一些类dtor似乎被多次生成。请问你们当中有人知道为什么吗

我使用下面的代码尝试并观察了上面提到的内容

在“test.h”中

在“test.cpp”中

我的问题如下

1) 为什么生成了多个DTR(基类-2,派生类-3)

2) 这些DTR之间有什么区别?如何有选择地使用这些多个DTR

我现在感觉到,为了实现C++项目的100%个功能覆盖,我们需要理解这一点,这样我就可以调用我的单元测试中所有的DoR。


如果有人能就上述问题给我答复,我将不胜感激。

首先,这些功能的用途在;请参阅“基本对象析构函数”、“完成对象析构函数”和“删除析构函数”下的定义。5.1.4中给出了损坏名称的映射

基本上:

  • D2是“基本对象析构函数”。它会破坏对象本身,以及数据成员和非虚拟基类
  • D1是“完整对象析构函数”。它还破坏虚拟基类
  • D0是“删除对象析构函数”。它执行完整对象析构函数所执行的所有操作,并调用
    operator delete
    来实际释放内存

如果没有虚拟基类,则D2和D1是相同的;GCC将在足够的优化级别上,实际将符号别名到这两者的相同代码中。

通常有两个构造函数变体(不负责/负责)和三个析构函数变体(不负责/负责/负责删除)

当使用
virtual
关键字处理从另一个类继承的类的对象时,如果该对象不是完整的对象(因此当前对象“不负责”构造或销毁虚拟基本对象),则使用不负责的ctor和dtor。此ctor接收指向虚拟基对象的指针并将其存储

负责所有其他情况的ctor和DTOR,即如果不涉及虚拟继承;如果类具有虚拟析构函数,负责删除dtor的指针将进入vtable插槽,而知道对象动态类型的作用域(即,对于具有自动或静态存储持续时间的对象)将使用负责删除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);
structfoo{
富(国际),;
虚拟~foo(void);
int-bar;
};
结构baz:虚拟foo{
baz(无效);
虚-baz(void);
};
结构quux:baz{
quux(无效);
虚~qux(void);
};
foo::foo(inti){bar=i;}
foo::~foo(void){return;}
baz::baz(void):foo(1){return;}
baz::~baz(void){return;}
qux::qux(void):foo(2),baz(){return;}
qux::~qux(void){return;}
baz-b1;
标准:自动ptr b2(新baz);
quxq1;
标准:自动测试q2(新测试);
结果:

  • foo
    baz
    qux
    的每个vtables中的数据或条目指向相应的负责删除数据或
  • b1
    b2
    baz()
    in-charge构造,它调用
    foo(1)
    in-charge
  • q1
    q2
    由负责的
    qux()
    构造,负责的是
    foo(2)
    baz()
    不负责,指针指向前面构造的
    foo
    对象
  • q2
    被负责的
    ~auto_ptr()
    破坏,它调用负责删除的虚拟dtor
    ~qux()
    调用负责删除的
    ~baz()
    不负责、
    ~foo()
    负责和
    操作员删除
  • q1
    ~qux()
    负责人破坏,它调用
    ~baz()
    不负责人和
    ~foo()
    负责人
  • b2
    被负责人
    ~auto_ptr()
    破坏,负责人调用虚拟数据或
    ~baz()
    负责人删除,负责人调用
    ~foo()
    负责人和
    操作员删除
  • b1
    ~baz()
    负责人破坏,它调用
    ~foo()
    负责人
qux
派生的任何人都将使用其不负责的ctor和dtor,并承担创建
foo
对象的责任


原则上,对于一个没有虚基的类来说,不负责变量是不需要的;在这种情况下,负责的变体有时被称为统一的,和/或负责和不负责的符号被别名为单个实现。

+1用于包含最小的完整示例程序。()您的基类是否有意使用非虚拟析构函数?一个小观察;您犯了罪,没有使基类析构函数成为虚拟的。很抱歉,我的示例不完整。是的,基类应该有虚拟析构函数,这样这些类对象就可以多态地使用。@Lyke:好吧,如果你知道你不会通过指向基类的指针来删除派生类,那没问题,我只是想确定。。。有趣的是,如果你真的让基本成员虚拟化,你会得到更多的析构函数。谢谢你给出了清晰的答案。现在我可以理解了,尽管我需要学习更多,因为我对虚拟继承这类东西不太熟悉。@Smg:在虚拟继承中,“虚拟”继承的类完全由派生最多的对象负责。也就是说,如果你有
struct B:virtual A
然后
struct C:B
,那么当销毁
B
时,你调用
B::D1
,后者依次调用
A::D2
,当
#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;
}
==== 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()
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);