В каком порядке вызываются деструкторы в C++?

«В каком порядке вызываются деструкторы в C++?» — вопрос из категории ООП, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В C++ деструкторы вызываются в строго определённом порядке, обратном порядку конструирования:

  1. Для одного объекта: Тело деструктора самого класса выполняется первым.
  2. Для членов класса (полей): Деструкторы полей вызываются после тела деструктора класса, в порядке, обратном их объявлению в определении класса.
  3. Для базовых классов: Деструкторы базовых классов вызываются после деструкторов всех полей, в порядке, обратном порядку наследования.
  4. Для объектов в стеке: При выходе из области видимости деструкторы локальных объектов вызываются в порядке LIFO (последний созданный — первый уничтоженный).

Пример, демонстрирующий порядок:

#include <iostream>
#include <string>

class Member1 {
public:
    ~Member1() { std::cout << "Member1 destroyed.n"; }
};

class Member2 {
public:
    ~Member2() { std::cout << "Member2 destroyed.n"; }
};

class Base {
public:
    ~Base() { std::cout << "Base destroyed.n"; }
};

class Derived : public Base {
    Member1 m1; // Объявлен первым
    Member2 m2; // Объявлен вторым
public:
    ~Derived() {
        std::cout << "Derived body.n"; // Тело деструктора
    }
};

int main() {
    Derived d;
    // При выходе из main() для объекта 'd' порядок будет:
    // 1. Тело ~Derived()
    // 2. ~Member2() (обратный порядок объявления полей)
    // 3. ~Member1()
    // 4. ~Base() (обратный порядок наследования)
    return 0;
}

Ожидаемый вывод:

Derived body.
Member2 destroyed.
Member1 destroyed.
Base destroyed.