gpt4 book ai didi

c++ - 有没有办法调用纯虚类的 "deleting destructor"?

转载 作者:可可西里 更新时间:2023-11-01 15:20:04 27 4
gpt4 key购买 nike

我在 Ubuntu Trusty 上使用 C++11 和 g++4.8。

考虑这个片段

class Parent {
public:
virtual ~Parent() = default;
virtual void f() = 0;
};

class Child: public Parent {
public:
void f(){}
};

使用调用

{
Child o;
o.f();
}
{
Parent * o = new Child;
delete o;
}
{
Child * o = new Child;
delete o;
}

我使用 gcov 生成我的代码覆盖率报告。它报告从未调用带有符号 _ZN6ParentD0Ev 的析构函数,而 _ZN6ParentD2Ev 是。

回答Dual emission of constructor symbolsGNU GCC (g++): Why does it generate multiple dtors?报告 _ZN6ParentD0Ev 是删除构造函数。

是否有在 Parent 类上调用此“删除析构函数”的情况?

附属问题:如果没有,是否有办法让 gcov/lcov 代码覆盖工具(在 Detailed guide on using gcov with CMake/CDash? 的回答后使用)在其报告中忽略该符号?

最佳答案

我认为这是因为您有 Child 对象,而不是 Parent 对象。

{
Child o;
o.f();
} // 1

{
Parent * o = new Child;
delete o;
} // 2

{
Child * o = new Child;
delete o;
} // 3

//1中,o被销毁,调用了Child完整对象析构函数。由于 Child 继承了 Parent,它会调用 base object destructor,即 _ZN6ParentD2Ev父级

//2中,o是动态分配和删除的,Child删除析构函数是叫。然后,它将调用Parent基础对象析构函数。在两者中,都调用了基础对象析构函数。

//3 相同。它等于 //2,除了 o 的类型。


我已经在 cygwin & g++ 4.8.3 & windows 7 x86 SP1 上测试过它。这是我的测试代码。

class Parent
{
public:
virtual ~Parent() { }
virtual void f() = 0;
};

class Child : public Parent
{
public:
void f() { }
};

int main()
{
{
Child o;
o.f();
}
{
Parent * o = new Child;
delete o;
}
{
Child * o = new Child;
delete o;
}
}

和编译 & gcov 选项:

$ g++ -std=c++11 -fprofile-arcs -ftest-coverage -O0 test.cpp -o test
$ ./test
$ gcov -b -f test.cpp

这是结果。

        -:    0:Source:test.cpp
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:1
-: 0:Programs:1
function _ZN6ParentC2Ev called 2 returned 100% blocks executed 100%
2: 1:class Parent
-: 2:{
-: 3:public:
function _ZN6ParentD0Ev called 0 returned 0% blocks executed 0%
function _ZN6ParentD1Ev called 0 returned 0% blocks executed 0%
function _ZN6ParentD2Ev called 3 returned 100% blocks executed 75%
3: 4: virtual ~Parent() = default;
call 0 never executed
call 1 never executed
branch 2 never executed
branch 3 never executed
call 4 never executed
branch 5 taken 0% (fallthrough)
branch 6 taken 100%
call 7 never executed
-: 5: virtual void f() = 0;
-: 6:};
-: 7:
function _ZN5ChildD0Ev called 2 returned 100% blocks executed 100%
function _ZN5ChildD1Ev called 3 returned 100% blocks executed 75%
function _ZN5ChildC1Ev called 2 returned 100% blocks executed 100%
7: 8:class Child : public Parent
call 0 returned 100%
call 1 returned 100%
call 2 returned 100%
branch 3 taken 0% (fallthrough)
branch 4 taken 100%
call 5 never executed
call 6 returned 100%
-: 9:{
-: 10:public:
function _ZN5Child1fEv called 1 returned 100% blocks executed 100%
1: 11: void f() { }
-: 12:};
-: 13:
function main called 1 returned 100% blocks executed 100%
1: 14:int main()
-: 15:{
-: 16: {
1: 17: Child o;
1: 18: o.f();
call 0 returned 100%
call 1 returned 100%
-: 19: }
-: 20: {
1: 21: Parent * o = new Child;
call 0 returned 100%
call 1 returned 100%
1: 22: delete o;
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
-: 23: }
-: 24: {
1: 25: Child * o = new Child;
call 0 returned 100%
call 1 returned 100%
1: 26: delete o;
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
-: 27: }
1: 28:}

如您所见,_ZN6ParentD2EvBase 的基础对象解构被调用,而 Base 的其他对象未被调用。

然而,_ZN5ChildD0Ev,删除 Child 的析构函数,被调用两次,_ZN5ChildD1EvChild 的完整对象析构函数>,被调用了三次,因为有 delete o;Child o;

但根据我的解释,_ZN5ChildD0Ev 应该被调用两次而 _ZN5ChildD1Ev 应该被调用一次,不是吗?为了找出原因,我这样做了:

$ objdump -d test > test.dmp

结果:

00403c88 <__ZN5ChildD0Ev>:
403c88: 55 push %ebp
403c89: 89 e5 mov %esp,%ebp
403c8b: 83 ec 18 sub $0x18,%esp
403c8e: a1 20 80 40 00 mov 0x408020,%eax
403c93: 8b 15 24 80 40 00 mov 0x408024,%edx
403c99: 83 c0 01 add $0x1,%eax
403c9c: 83 d2 00 adc $0x0,%edx
403c9f: a3 20 80 40 00 mov %eax,0x408020
403ca4: 89 15 24 80 40 00 mov %edx,0x408024
403caa: 8b 45 08 mov 0x8(%ebp),%eax
403cad: 89 04 24 mov %eax,(%esp)
403cb0: e8 47 00 00 00 call 403cfc <__ZN5ChildD1Ev>
403cb5: a1 28 80 40 00 mov 0x408028,%eax
403cba: 8b 15 2c 80 40 00 mov 0x40802c,%edx
403cc0: 83 c0 01 add $0x1,%eax
403cc3: 83 d2 00 adc $0x0,%edx
403cc6: a3 28 80 40 00 mov %eax,0x408028
403ccb: 89 15 2c 80 40 00 mov %edx,0x40802c
403cd1: 8b 45 08 mov 0x8(%ebp),%eax
403cd4: 89 04 24 mov %eax,(%esp)
403cd7: e8 a4 f9 ff ff call 403680 <___wrap__ZdlPv>
403cdc: a1 30 80 40 00 mov 0x408030,%eax
403ce1: 8b 15 34 80 40 00 mov 0x408034,%edx
403ce7: 83 c0 01 add $0x1,%eax
403cea: 83 d2 00 adc $0x0,%edx
403ced: a3 30 80 40 00 mov %eax,0x408030
403cf2: 89 15 34 80 40 00 mov %edx,0x408034
403cf8: c9 leave
403cf9: c3 ret
403cfa: 90 nop
403cfb: 90 nop

是的,因为 _ZN5ChildD0Ev 调用了 _ZN5ChildD1Ev,所以 _ZN5ChildD1Ev 被调用了三次。 (1 + 2) 我想这只是 GCC 的实现 - 用于减少重复。

关于c++ - 有没有办法调用纯虚类的 "deleting destructor"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25662174/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com