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

时间:2018-09-20 13:03:16

标签: c++ destructor

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

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

最干净的解决方法是什么?

这是我的样品:

#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

1 个答案:

答案 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中进行详细说明。