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

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

2.2 Middle🔥 171 комментариев
#Исключения и обработка ошибок#ООП и проектирование#Язык C++

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Будет ли вызван деструктор при исключении в конструкторе?

Краткий ответ: Нет, деструктор объекта НЕ будет вызван, если его конструктор бросил исключение. Однако деструкторы УЖЕ инициализированных членов класса вызваны БУДУТ.

Почему деструктор самого объекта не вызывается?

Это ключевое правило в C++: если конструктор завершился с исключением, объект считается не полностью инициализированным, а поэтому он не существует. Раз объекта нет, деструктор вызывать нечему.

class Resource {
public:
    Resource(int id) {
        std::cout << "Конструктор вызван\n";
        if (id < 0) {
            throw std::invalid_argument("ID не может быть отрицательным");
        }
    }
    
    ~Resource() {
        std::cout << "Деструктор вызван\n";
    }
};

int main() {
    try {
        Resource r(-1);  // Конструктор бросит исключение
        // Деструктор НЕ будет вызван
    } catch (const std::exception& e) {
        std::cout << "Перехвачено: " << e.what() << "\n";
    }
}

Вывод: только строка "Конструктор вызван", без "Деструктор вызван".

А что с членами класса?

Здесь ситуация сложнее. Если конструктор инициализировал членов класса перед тем, как бросить исключение, деструкторы этих членов БУДУТ вызваны в обратном порядке инициализации:

class Logger {
public:
    Logger(const std::string& name) { 
        std::cout << "Logger: " << name << " создан\n"; 
    }
    ~Logger() { 
        std::cout << "Logger уничтожен\n"; 
    }
};

class Container {
public:
    Logger log1{"log1"};
    Logger log2{"log2"};
    
    Container() {
        std::cout << "Container конструктор начался\n";
        throw std::runtime_error("Ошибка в конструкторе");
    }
    
    ~Container() {
        std::cout << "Container деструктор\n";
    }
};

int main() {
    try {
        Container c;
    } catch (...) {}
}

Вывод:

Logger: log1 создан
Logger: log2 создан
Container конструктор начался
Logger уничтожен  // log2 в обратном порядке
Logger уничтожен  // log1 в обратном порядке

Деструктор самого Container НЕ вызван, но деструкторы его членов — ДА.

Практические следствия

  1. RAII паттерн: используй членские переменные типов, у которых есть деструкторы (std::string, std::vector, std::unique_ptr). Они очистят ресурсы автоматически.

  2. Инициализация и исключения: если конструктор должен быть безопасным, инициализируй члены в правильном порядке и бросай исключения рано.

class SafeResource {
    std::unique_ptr<int> ptr;
    std::vector<int> data;
public:
    SafeResource(int size) 
        : ptr(std::make_unique<int>(size)), data(size) {
        // Если бросим исключение здесь,
        // ptr и data очищены автоматически
        if (size > 1000000) {
            throw std::out_of_range("Слишком большой размер");
        }
    }
};
  1. Function-try-block: в исключительных случаях можно перехватить исключение прямо в конструкторе:
MyClass::MyClass() try 
    : member1(), member2() {
    // код конструктора
} catch (const std::exception& e) {
    // обработка, но нужно пробросить исключение дальше
    throw;  // иначе объект считается инициализированным!
}

Вывод

Деструктор объекта, конструктор которого бросил исключение, не вызывается. Но это не проблема, если ты используешь RAII и умные указатели — они позаботятся об очистке ресурсов за счёт деструкторов своих членов.

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