- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我在 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 symbols和 GNU 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:}
如您所见,_ZN6ParentD2Ev
,Base
的基础对象解构被调用,而 Base
的其他对象未被调用。
然而,_ZN5ChildD0Ev
,删除 Child
的析构函数,被调用两次,_ZN5ChildD1Ev
,Child
的完整对象析构函数>,被调用了三次,因为有 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/
例如,下面是否泄漏? Foo ( ) { std:map myMap; myMap[std::string("Bar")] = 2983; } 我相信它不会泄漏,但找不到关于这一点的具体文
有没有办法在类析构函数之前调用字段析构函数? 假设我有 2 个类 Small 和 Big,Big 包含一个 Small 的实例作为它的字段因此: class Small { public: ~
阅读 Herb Sutter,我可以看到这一点: Guideline #4: A base class destructor should be either public and >virtual,
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 4 年前。 Improve
我只有 1 行代码,这是: pcrecpp::RE re("abc"); 在函数内部 OnBnClickedButtonGo() .这个函数在Release模式下会失败,但是在debug模式下可以正常
我最近参加了一个采访,那个人问我什么是 build 和破坏的顺序。我解释说, build 是从一个基地到另一个 child ,从一个 child 到另一个基地的破坏。 采访者很想知道从派生到基地发生破
如果我在 vector 中动态分配一个类的对象,如果我使用 clear() 是否会调用每个对象的析构函数? 最佳答案 “动态分配”到底是什么意思?如果您使用 vector那你很好。如果您通过 vect
我正在尝试使用手动内存管理来管理昂贵对象的生命周期,在我的单元测试期间,我的程序似乎因 destroy(bar) 下的主要方法中的访问冲突而崩溃在这个例子中。这是我遇到访问冲突问题的最小示例。 我不明
我只是创建一个简单的列表,然后销毁它。出了点问题,我总是收到这个恼人的错误消息: Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) 代码如下: #i
class TsDatabasePool { private: TsDatabasePool(int numDBConn, std::string& DBName, std::string&
在一个项目中,我遇到了以下问题: 我有一个非常简单的继承方案(我需要继承而不是组合): 类基础 ->类DerivedA ->类DerivedB ->类DerivedC A、B 和 C 派生自 Base
我试图在我创建的矩阵类上对 + 和 = 运算符使用运算符重载。要么是构造函数或析构函数导致了问题,要么都不是(尽管我将它们中的每一个都变灰了,并且代码似乎可以工作)。有人可以帮我理解是什么导致了这种奇
我正在用 SDL 编写基于图 block 的 map ,Map 类的构造函数用于设置用于表示包含的每个 MapCell 对象的图像在里面。但是,我的 Sprite 类的析构函数有问题,该类用于释放对象
这个问题在这里已经有了答案: What destructors are run when the constructor throws an exception? (3 个答案) 关闭 8 年前。
我在 Ubuntu Trusty 上使用 C++11 和 g++4.8。 考虑这个片段 class Parent { public: virtual ~Parent() = default;
我在我们的一个客户环境中遇到问题 - 当我在 OnAppExit(或析构函数)中使用 AfxGetApp()->WriteProfileString 时它不起作用。我无法在任何地方复制它。我追踪到 O
C# Language Specification 3.0 的第 10.13 节,析构函数声明如下: Destructors are not inherited. Thus, a class has
我正在试验专门的析构函数。这段代码完全有效并且编译得很好: #include using namespace std; template class Cat { public: ~Cat(
所以我正在尝试制作一个递归链表。它看起来有点像这样: class List { int cur; //For now List* nxt; public: List()
我的代码如下: class TimeManager { public: virtual ~TimeManager(); }; class UserManager : virtual public T
我是一名优秀的程序员,十分优秀!