下面摘自 http://en.cppreference.com/w/cpp/language/destructor
Trivial destructor
The destructor for class T
is trivial if all of the following is true:
- The destructor is not user-provided (meaning, it is implicitly-defined or defaulted)
- The destructor is not virtual (that is, the base class destructor is not virtual)
- All direct base classes have trivial destructors
- All non-static data members of class type (or array of class type) have trivial destructors
A trivial destructor is a destructor that performs no action. Objects with trivial destructors don't require a delete-expression and may be disposed of by simply deallocating their storage. All data types compatible with the C language (POD types) are trivially destructible.
Implicitly-defined destructor
If the implicitly-declared destructor is not deleted or trivial, it is defined (that is, a function body is generated and compiled) by the compiler. This implicitly-defined destructor has an empty body.
As with any implicitly-defined special member function, the exception specification of the implicitly-defined destructor is non-throwing unless it directly invokes a function with a different exception specification (e.g. when it must call a user-defined destructor for a member or a base subobject with a different exception specification).
trivial destructor 和 implicitly-defined destructor 都是编译器自动产生的,但是前者在目标文件中不存在,后者在目标文件中存在可以设置断点调试。先看一段代码:
class A
{
public:
virtual void foo(void) {}
A* m_ptr;
};
class C
{
int *p;
public:
C() {p = new int;}
~C();
};
C::~C()
{
delete p;
}
class B : public A
{
public:
virtual void Bob(){}
C c;
};
int main(void)
{
B *pB = new B;
delete pB;
return 0;
}
用 gdb调试:
(gdb) b B::~B()
Breakpoint 1 at 0x804875e: file test_destructor.cpp, line 22.
(gdb) list 22
17 };
18 C::~C()
19 {
20 delete p;
21 }
22 class B : public A
23 {
24 public:
25 virtual void Bob(){}
26 C c;
(gdb) disass B::~B(void)
Dump of assembler code for function B::~B():
0x08048758 <+0>: push %ebp
0x08048759 <+1>: mov %esp,%ebp
0x0804875b <+3>: sub $0x8,%esp
0x0804875e <+6>: mov 0x8(%ebp),%eax
0x08048761 <+9>: movl $0x8048820,(%eax)
0x08048767 <+15>: mov 0x8(%ebp),%eax
0x0804876a <+18>: add $0x8,%eax
0x0804876d <+21>: sub $0xc,%esp
0x08048770 <+24>: push %eax
0x08048771 <+25>: call 0x804865c <C::~C()>
0x08048776 <+30>: add $0x10,%esp
0x08048779 <+33>: leave
0x0804877a <+34>: ret
End of assembler dump.
(gdb) where
#0 C::~C (this=0x804fa18, __in_chrg=<optimized out>) at test_destructor.cpp:20
#1 0x08048776 in B::~B (this=0x804fa10, __in_chrg=<optimized out>) at test_destructor.cpp:22
#2 0x080486b6 in main () at test_destructor.cpp:32
(gdb)
可以看到, 编译器自动产生的析构函数也调用了 C的析构函数。
$ objdump -Ct test_destructor | grep -E "B\("
08048726 w F .text 00000032 B::B()
08048758 w F .text 00000023 B::~B()
08048726 w F .text 00000032 B::B()
08048758 w F .text 00000023 B::~B()
$ objdump -Ct test_destructor | grep -E "A\("
08048718 w F .text 0000000e A::A()
08048718 w F .text 0000000e A::A()
可以看到,目标文件里有 ~C()的符号, 蛋没有 ~A().
Destruction sequence
For both user-defined or implicitly-defined destructors, after the body of the destructor is executed, the compiler calls the destructors for all non-static non-variant members of the class, in reverse order of declaration, then it calls the destructors of all direct base classes in reverse order of construction (which in turn call the destructors of their members and their base classes, etc), and then, if this object is of most-derived class, it calls the destructors of all virtual bases.
Even when the destructor is called directly (e.g. obj.~Foo();), the return statement in ~Foo() does not return control to the caller immediately: it calls all those member and base destructors first.