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

Можно ли в деструкторе объекта породить другой объект?

2.3 Middle🔥 101 комментариев
#ООП и проектирование#Язык C++

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

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

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

Создание объектов в деструкторе

Краткий ответ

Технически да, можно создать объект в деструкторе. Компилятор позволит это сделать. Однако это является плохой практикой и может привести к серьёзным проблемам.

Почему это работает

Деструктор - это обычная функция-член объекта, и в ней можно выполнять любые операции на C++:

class Logger {
public:
    Logger(const std::string& msg) : message(msg) {}
    
    ~Logger() {
        // Можно создавать объекты
        std::string log_entry = "Destroying object with message: " + message;
        std::cout << log_entry << std::endl;
    }
    
private:
    std::string message;
};

Проблемы и опасности

1. Проблемы с исключениями

Если в деструкторе выбросится исключение, произойдёт вызов std::terminate():

class BadDestructor {
public:
    ~BadDestructor() {
        SomeObject obj;  // Создали объект
        if (!obj.IsValid()) {
            throw std::runtime_error("Object invalid");  // ОПАСНО!
        }
    }
};

2. Утечки ресурсов при создании новых объектов

Если создаёте объекты динамически в деструкторе, они должны где-то удаляться:

class ResourceManager {
public:
    ~ResourceManager() {
        // ПЛОХО - утечка памяти!
        SomeObject* new_obj = new SomeObject();
        new_obj->Cleanup();
    }
};

3. Неопределённый порядок уничтожения

Если в деструкторе создаёте объекты, которые удерживают ссылки на исходный объект, возможна undefined behavior:

class Observer {
public:
    Observer(Parent* p) : parent(p) {}
    void Notify() { parent->OnNotify(); }
    
private:
    Parent* parent;
};

class Parent {
public:
    ~Parent() {
        observer = new Observer(this);
        observer->Notify();  // Вызовет Parent::OnNotify()
        // Но Parent уже уничтожается!
    }
    void OnNotify() {}
    
private:
    Observer* observer;
};

4. Нарушение контракта RAII

Результаты создания объектов в деструкторе непредсказуемы и усложняют анализ памяти.

Когда это может быть приемлемо

Только в очень ограниченных случаях с чистыми данными:

class SimpleLogger {
public:
    ~SimpleLogger() {
        std::string timestamp = GetCurrentTime();
        std::string log_msg = "Object destroyed at " + timestamp;
    }
};

Правила и best practices

✓ Правильно:

  • Деструктор должен только освобождать ресурсы
  • Не создавайте объекты в деструкторе
  • Не выбрасывайте исключения в деструкторе
  • Деструктор должен быть noexcept
class Correct {
public:
    ~Correct() noexcept {
        if (file) {
            file->Close();
        }
        if (connection) {
            connection->Disconnect();
        }
    }
};

✗ Неправильно:

  • Создание новых объектов
  • Выброс исключений
  • Долгие операции
  • Динамическое выделение памяти

Альтернатива: explicit cleanup method

Если нужна сложная логика очистки, используйте отдельный метод:

class ResourceManager {
public:
    void Cleanup() {
        Logger log;
        for (auto& resource : resources) {
            resource.Release();
        }
    }
    
    ~ResourceManager() noexcept {
        try {
            Cleanup();
        } catch (...) {
        }
    }
};

Заключение

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