C++析构函数调用两次,堆栈分配的复合对象



>我有一个复合类(包含其他实例的实例,也不是指针,也不是引用(。 当容器实例被销毁时,将调用包含实例的析构函数(我对此没意见,这是逻辑(。但问题是,如果包含的实例是堆栈分配的析构函数,则在超出范围时再次调用析构函数。

这是编码错误还是编译器问题?

修复它最干净的方法是什么?

这是我的示例:

#include <iostream>
using std::cout;
using std::endl;
class A {
public:
int i;
A(int i_) : i(i_) {
cout << "A(): " << i << endl;
}
~A() {
cout << "~A(): " << i << endl;
}
};
class B {
public:
A a;
int b;
B(const A& a_) : a(a_) {
cout << "B(): " << a.i << endl;
}
~B() {
cout << "~B(): " << a.i << endl;
}
};
int main(void) {
for(int c = 0; c < 3; ++c) {
A a(c+1);
B b(a);
cout << b.a.i << endl;
}
return 0;
}

输出为:

A(): 1
B(): 1
1
~B(): 1
~A(): 1
~A(): 1
A(): 2
B(): 2
2
~B(): 2
~A(): 2
~A(): 2
A(): 3
B(): 3
3
~B(): 3
~A(): 3
~A(): 3

编译器是 gcc 7.3.0

每个对象只调用一次析构函数。您在输出中看不到的是,当您构造b时,您可以使用复制构造函数(在您的例子中是编译器生成的(创建a的副本。这不会产生任何输出,但当然也会调用副本的析构函数。

如果我们将输出添加到复制构造函数,我们可以看到实际发生的情况:

A(const A& a_) : i(a_.i) {
cout << "A(const A&): " << i << endl;
}

输出显示每个A被复制一次,导致"重复"(不是真正的(析构函数调用(现场演示(。如果您想避免复制对象,请查看 C++11 的std::move,这在本站点的其他地方有深入的解释。

最新更新