← Назад ко всем вопросам

Будет ли вызван деструктор для объекта, конструктор которого бросил исключение

1️⃣ Как кратко ответить

Деструктор для объекта, конструктор которого бросил исключение, не будет вызван, так как объект не был полностью создан. Однако, если в конструкторе были выделены ресурсы, они должны быть освобождены вручную или с помощью механизмов управления ресурсами, таких как RAII.

2️⃣ Подробное объяснение темы

В C++ конструктор объекта отвечает за его инициализацию. Если в процессе инициализации происходит ошибка, конструктор может выбросить исключение. В этом случае объект считается не полностью созданным, и его деструктор не будет вызван автоматически. Это связано с тем, что деструктор вызывается только для полностью созданных объектов.

Рассмотрим пример:

#include <iostream>
#include <stdexcept>
​
class Resource {
public:
    Resource() {
        std::cout << "Resource acquired\n";
    }
    ~Resource() {
        std::cout << "Resource released\n";
    }
};
​
class MyClass {
public:
    MyClass() {
        resource = new Resource(); // Выделение ресурса
        throw std::runtime_error("Error during construction"); // Исключение
    }
    ~MyClass() {
        delete resource; // Освобождение ресурса
    }
private:
    Resource* resource;
};
​
int main() {
    try {
        MyClass obj; // Попытка создать объект
    } catch (const std::exception& e) {
        std::cout << "Exception caught: " << e.what() << '\n';
    }
    return 0;
}

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

  • Класс Resource представляет некоторый ресурс, который необходимо освободить после использования.
  • Конструктор MyClass выделяет ресурс с помощью new и затем выбрасывает исключение.
  • Деструктор MyClass освобождает ресурс, но он не будет вызван, так как объект MyClass не был полностью создан из-за исключения.

Когда исключение выбрасывается в конструкторе, необходимо убедиться, что все выделенные ресурсы освобождены. В примере выше, если бы не было механизма для освобождения ресурса, возникла бы утечка памяти.

Для предотвращения утечек ресурсов в таких ситуациях рекомендуется использовать идиому RAII (Resource Acquisition Is Initialization). Это означает, что ресурсы должны быть обернуты в объекты, которые автоматически освобождают их в своих деструкторах. Например, можно использовать std::unique_ptr:

#include <iostream>
#include <stdexcept>
#include <memory>
​
class Resource {
public:
    Resource() {
        std::cout << "Resource acquired\n";
    }
    ~Resource() {
        std::cout << "Resource released\n";
    }
};
​
class MyClass {
public:
    MyClass() {
        resource = std::make_unique<Resource>(); // Автоматическое управление ресурсом
        throw std::runtime_error("Error during construction"); // Исключение
    }
private:
    std::unique_ptr<Resource> resource;
};
​
int main() {
    try {
        MyClass obj; // Попытка создать объект
    } catch (const std::exception& e) {
        std::cout << "Exception caught: " << e.what() << '\n';
    }
    return 0;
}

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

  • std::unique_ptr автоматически освобождает ресурс, когда объект MyClass разрушается, даже если его конструктор выбросил исключение.
  • Это гарантирует, что ресурсы будут корректно освобождены, предотвращая утечки памяти.

Таким образом, при проектировании классов в C++ важно учитывать возможность выброса исключений в конструкторах и использовать подходящие механизмы для управления ресурсами.

Тема: Исключения / noexcept / Safety
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки