我有一个复合类(包含其他实例的实例,也没有指针,也没有引用)。 当容器实例被销毁时,将调用包含实例的析构函数(我很确定,这是逻辑)。但是问题在于,如果所包含的实例是堆栈分配的,则在超出范围时会再次调用析构函数。
是编码错误还是编译器问题?
最干净的解决方法是什么?
这是我的样品:
#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
答案 0 :(得分:4)
每个对象只调用一次析构函数。在输出中看不到的是,在构造b
时,您使用复制构造函数(在您的情况下是编译器生成的)创建了a
的副本 )。不会产生任何输出,但是当然也调用副本的析构函数。
如果将输出添加到复制构造函数中,我们可以看到实际发生的情况:
A(const A& a_) : i(a_.i) {
cout << "A(const A&): " << i << endl;
}
输出显示每个A
被复制一次,从而导致“复制的”(不是真的)析构函数调用(live demo)。如果要避免复制对象,请查看C ++ 11的std::move
,将在elsewhere on this site中进行详细说明。