繁体   English   中英

为什么析构函数为同一个对象调用了两次?

[英]Why is the destructor called twice for the same object?

在以下来自核心转储A2的回溯中:~A2被调用两次:

#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来自A1,B2来自B1。 只有B2有一个默认的析构函数,所有基类析构函数都是虚拟的。

代码看起来像这样:

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
//...
}

我无法理解为什么A2 ::〜A2被同一个对象调用两次(回溯中的this指针对4帧和5帧都有相同的值)。

如果我转到第4帧并进行反汇编,则会从第5帧反汇编代码中打印出非常不同的结果(大约90行汇编代码与大约20行汇编代码)。

我把这个例子简化为

#include <cassert>
class A1 {
public:
    virtual ~A1() {
        assert(false);
    }
};

class A2 : public A1 {
};

int main() {
    A1* a = new A2;
    delete a;
    return 0;
}

使用assert来触发核心转储。

使用g ++ 4.7.2进行编译,我们在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

而使用g ++ 4.3.2编译的相同代码的回溯看起来相似,但A2 ::〜A2只有一个帧。

两个回溯都是用相同版本的gdb(7.5.1)提取的。

所以它是g ++ 4.7生成的代码的工件,没有什么可担心编译的二进制文件的行为。 它不是对析构函数的真正双重调用。

这可能是你的场景(但你没有向我们展示这部分代码)......

如果类E拥有指向A2的私有成员指针,并且它没有复制构造函数或operator = ....

然后,可能存在这样的情况:使用默认的复制构造函数或operator =将类型E的Object复制到类型E的另一个对象(变量)。

这将导致成员的浅拷贝,这将导致两个对象现在指向同一个对象A1。

当对象E被销毁时,它们都试图删除相同的A2对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM