C ++ деструктор вызывается дважды с выделенными составными объектами в стеке - PullRequest
0 голосов
/ 20 сентября 2018

У меня есть составной класс (экземпляр, содержащий другой экземпляр, ни указатель, ни ссылку).Когда экземпляр контейнера уничтожается, вызывается деструктор содержащегося экземпляра (я согласен с этим, это логика).Но проблема в том, что если содержащийся экземпляр является выделенным стеком, деструктор вызывается еще раз при выходе за пределы области действия.

Это ошибка кодирования или проблема компилятора?

Какой самый чистый способисправить это?

Вот мой пример:

#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 голосов
/ 20 сентября 2018

Деструктор вызывается только один раз для каждого объекта.В выводе вы не видите, что когда вы создаете b, вы создаете копию из a, используя конструктор копирования (который в вашем случае генерируется компилятором).Это не производит никакого вывода, но, конечно, деструктор копии также называется.

Если мы добавим вывод в конструктор копирования, мы можем увидеть, что на самом деле происходит:

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

Вывод показывает, что каждый A копируется один раз, что приводит к «дублированным» (не совсем) вызовам деструктора ( live demo ).Если вы хотите избежать копирования объекта, посмотрите на C ++ 11 std::move, который подробно объясняется в другом месте на этом сайте .

...