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

О чем следует помнить при выбросе исключений в конструкторе?

Sobes Copilot

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

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

sobes.tech AI

  1. Утечки ресурсов: Если конструктор выбросил исключение после того, как часть ресурсов была выделена (память, дескрипторы файлов и т.д.), но до завершения инициализации объекта, эти ресурсы могут не быть освобождены, если деструктор объекта не будет вызван.
  2. Частично построенные объекты: Объект, конструктор которого выбросил исключение, считается недостроенным. Деструктор для такого объекта не вызывается автоматически.
  3. RAII (Resource Acquisition Is Initialization): Использование RAII-оберток (например, std::unique_ptr, std::vector, std::lock_guard) для управления ресурсами помогает автоматически освобождать их при выбросе исключения, поскольку деструкторы RAII-объектов, используемых в конструкторе, вызываются при раскрутке стека.
  4. Порядок инициализации членов: Члены класса инициализируются в порядке их объявления, а не в порядке их инициализации в списке инициализации конструктора. Если инициализация члена выбросила исключение, то члены, проинициализированные до этого, могут потребовать очистки.
  5. noexcept: Конструктор класса с noexcept спецификатором не должен выбрасывать исключения. Если исключение выбрасывается в noexcept конструкторе, программа будет завершена (default behaviour).
  6. new оператор: Сам оператор new может выбросить исключение std::bad_alloc при нехватке памяти.

Пример использования RAII:

#include <memory>
#include <stdexcept>

class Resource {
public:
    Resource() { /* Выделение ресурса */ }
    ~Resource() { /* Освобождение ресурса */ }
};

class MyClass {
    std::unique_ptr<Resource> res1;
    std::unique_ptr<Resource> res2;
public:
    MyClass() : res1(std::make_unique<Resource>()) {
        // Если здесь будет выброшено исключение, res1 освободится
        if (/* условие для исключения */ true) {
            throw std::runtime_error("Error during construction");
        }
        res2 = std::make_unique<Resource>(); // Эта строка не будет достигнута
    }
};

int main() {
    try {
        MyClass obj;
    } catch (const std::exception& e) {
        // res1 будет освобожден автоматически благодаря unique_ptr
        // res2 никогда не был создан
    }
    return 0;
}