Why is the destructor called twice for the same object?

In the following reverse direction from the main dump A2: ~ A2 is called twice:

#0 0x086f5371 in B1::~B1 (this=0xe6d3a030, __in_chrg=<value optimized out>) at /fullpath/b1.cpp:400 #1 0x086ffd43 in ~B2 (this=0xe6d3a030, __in_chrg=<value optimized out>) at /fullpath/b2.h:21 #2 B2::~B2 (this=0xe6d3a030, __in_chrg=<value optimized out>) at /fullpath/b2.h:21 #3 0x086ea516 in A1::~A1 (this=0xe3e93958, __in_chrg=<value optimized out>) at /fullpath/a1.cpp:716 #4 0x0889b85d in A2::~A2 (this=0xe3e93958, __in_chrg=<value optimized out>) at /fullpath/a2.cpp:216 #5 0x0889b893 in A2::~A2 (this=0xe3e93958, __in_chrg=<value optimized out>) at /fullpath/a2.cpp:216 #6 0x0862c0f1 in E::Identify (this=0xe8083e20, t=PT_UNKNOWN) at /fullpath/e.cpp:713 

A2 is obtained from A1 and B2 is obtained from B1. Only B2 has a default destructor, all base class destructors are virtual.

The code looks something like this:

e.cpp:

 E::E(){ //... some code ... myA1= new A2(); } void E::Identify(){ //... if(myA1){ delete myA1; //line 713 of e.cpp myA1 = NULL; } } 

a2.cpp:

 A2::~A2(){ //... if (sd) //sd is not null here and also not made null after deletion { delete [] sd; //when called the second time shouldn't it crash here? } //... } // line 216 of a2.cpp 

a1.cpp

 A1::A1(){ //... myB1 = new B2(); //... } A1::~A1(){ //... delete myB1; //line 716 of a1.cpp //... } 

I cannot understand why A2 :: ~ A2 is called twice for the same object (this pointer in backtrace has the same value for 4 and 5 frames).

If I go to frame 4 and parse it, it produces a completely different result from frame 5 of the disassembled frame (about 90 lines of assembly code about 20 lines of assembly code).

+6
source share
2 answers

I compared the example with

 #include <cassert> class A1 { public: virtual ~A1() { assert(false); } }; class A2 : public A1 { }; int main() { A1* a = new A2; delete a; return 0; } 

with a statement to trigger a core dump.

Compilation with g ++ 4.7.2, we get double destruction of backtrace in gdb

 #0 0x00007f16060e92c5 in raise () from /usr/lib/libc.so.6 #1 0x00007f16060ea748 in abort () from /usr/lib/libc.so.6 #2 0x00007f16060e2312 in __assert_fail_base () from /usr/lib/libc.so.6 #3 0x00007f16060e23c2 in __assert_fail () from /usr/lib/libc.so.6 #4 0x00000000004007c8 in A1::~A1 (this=0xf60010, __in_chrg=<optimized out>) at double.cpp:6 #5 0x000000000040084d in A2::~A2 (this=0xf60010, __in_chrg=<optimized out>) at double.cpp:10 #6 0x0000000000400880 in A2::~A2 (this=0xf60010, __in_chrg=<optimized out>) at double.cpp:10 #7 0x000000000040078c in main () at double.cpp:15 

while backtracking of the same code compiled with g ++ 4.3.2 looks similar, but with only one frame for A2 :: ~ A2.

Both reverse loops were retrieved using the same gdb version (7.5.1).

So, this is an artifact of the code generated by g ++ 4.7, and there is nothing to worry about the behavior of the compiled binary. This is not a true double call to the destructor.

+5
source

It could be your script (but you didn’t tell us this part of the code) ...

If class E contains a private element pointer to A2 and does not have a copy constructor or operator = ....

Then a situation may arise when an object of type E is copied to another object (variable) of type E with the default copy constructor or = operator.

This will result in a shallow copy of the members, which will result in both objects now pointing to the same object.

When object E is destroyed, both of them try to delete the object of the same A2 .

+2
source

All Articles