Объекты · Классы и память

Время жизни и RAII

Главная идея C++: ресурс освобождается сам

~30 мин 6 шагов

После урока ты сможешь

  • Предсказывать, когда объект создаётся и уничтожается
  • Писать деструктор, который освобождает ресурс
  • Объяснить, почему в C++ нет и не нужен сборщик мусора

Шаг 1 из 6

Когда объект рождается и умирает

У каждого объекта в C++ есть точное время жизни. Локальная переменная создаётся там, где объявлена, и уничтожается на закрывающей фигурной скобке своего блока. Это видно, если написать класс, который сообщает о своём рождении и смерти:

main.cpp
#include <print>
#include <string>
#include <utility>
​
class Noisy {
public:
    explicit Noisy(std::string name) : name_(std::move(name)) {
        std::println("+ {}", name_);
    }
    ~Noisy() {
        std::println("- {}", name_);
    }
​
private:
    std::string name_;
};
​
int main() {
    Noisy a("a");
    {
        Noisy b("b");
        Noisy c("c");
        std::println("внутри блока");
    }   // здесь умирают c, затем b
    std::println("после блока");
}   // здесь умирает a

Метод ~Noisy() — деструктор: он вызывается автоматически, когда объект уничтожается. Его никогда не вызывают вручную.

Два правила, которые стоит запомнить:

  1. Объект уничтожается при выходе из своей области видимости, каким бы путём ни произошёл выход: конец блока, return, break, исключение.
  2. Объекты одной области уничтожаются в обратном порядке создания. c создан последним и умирает первым: то, что создано позже, может зависеть от созданного раньше.

Проверь себя

Что выведет программа?

main.cpp
#include <print>
​
struct Tag {
    char name;
    ~Tag() { std::print("{}", name); }
};
​
int main() {
    Tag a{'a'};
    {
        Tag b{'b'};
        Tag c{'c'};
    }
    Tag d{'d'};
    std::println("");
}
Enter — проверить, Shift+Enter — новая строка