Назад к вопросам
Middle+
103
questionbank

В чем заключается особенность выбрасывания исключений в конструкторах и деструкторах?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Выбрасывание исключений из конструктора приводит к тому, что объект не будет полностью создан. В этом случае автоматически вызываются деструкторы для всех уже проинициализированных подобъектов (членов-данных и базовых классов).

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

#include <iostream>
#include <stdexcept>

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired" << std::endl;
    }
    ~Resource() noexcept { // Деструктор не должен выбрасывать исключения
        try {
            // Потенциально опасная операция, которая может выбросить исключение
            // std::cout << "Resource released (potentially throwing op)" << std::endl;
            // throw std::runtime_error("Error during release");
            std::cout << "Resource released" << std::endl;
        } catch (...) {
            // Логирование или другая обработка ошибки без повторного выброса
            std::cerr << "Exception caught in Resource destructor!" << std::endl;
            // std::abort(); // Крайний случай для неисправимых ошибок
        }
    }
};

class MyClass {
private:
    Resource res1;
    Resource res2; // Этот ресурс будет создан после res1
    Resource res3;

public:
    MyClass(int value) : res1(), res2(), res3() {
        std::cout << "MyClass constructor started" << std::endl;
        if (value < 0) {
            // Исключение в конструкторе
            // res1 и res2 уже созданы и будут автоматически уничтожены
            throw std::runtime_error("Negative value not allowed");
        }
        std::cout << "MyClass constructor finished" << std::endl;
    }

    ~MyClass() {
        std::cout << "MyClass destructor called" << std::endl;
        // Деструкторы res1, res2, res3 будут вызваны автоматически
    }
};

int main() {
    try {
        MyClass obj1(10); // Успешное создание
    } catch (const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
    }

    std::cout << "---" << std::endl;

    try {
        MyClass obj2(-5); // Исключение в конструкторе
    } catch (const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
    }

    std::cout << "---" << std::endl;

    // Пример с потенциальным исключением в деструкторе (закомментировано)
    // MyClass obj3(20);
    // (объект obj3 будет уничтожен при выходе из main, вызывая деструктор)

    return 0;
}