Безопасен ли вызов деструктора из блока catch в конструкторе? - PullRequest
0 голосов
/ 19 февраля 2019

В моем конструкторе я должен уничтожить все оставшиеся ресурсы, если какой-либо код в нем выбрасывается.Я хотел бы избежать написания дублирующего кода, поэтому я просто вызываю деструктор в блоке catch, который освобождает любой созданный ресурс.Это безопасно?

Я знаю, что деструктор не вызывается, если конструктор выдает, поэтому я попытался скомпилировать некоторый код в msvc, и ничего не кажется неправильным, но я не уверен, что это просто удача.

Object::Object(){
    try{
        // Initialize multiple resources here.
    }catch(...){
        this->~Object(); // Is this safe?
        throw;
    }
}

Object::~Object(){
    // release multiple resources, if initialized.
}

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Несмотря на то, что деструкторы выглядят как обычные методы, а синтаксис явного уничтожения выглядит как вызов этого метода, на самом деле он не просто вызывает этот метод.Среди других специфичных для реализации вещей, он также вызывает деструкторы базовых классов и членов данных.Бросок исключения из конструктора также вызывает вызов всех этих деструкторов.Итак, ~Object(), за которым следует throw, вызовут их дважды, что, вероятно, приведет к катастрофическим последствиям.

Просто переместите код очистки в обычный метод, как кто-то предложил в комментарии.

Естьаналогичная синтаксическая проблема с синтаксисом вызова функции для создания временного объекта и с new / delete и operator new / operator delete.Никто из них просто не вызывает функции с одинаковыми именами, хотя, похоже, они должны.

0 голосов
/ 19 февраля 2019

Во-первых, нормально вызывает функцию-член :

Функции-члены, включая виртуальные функции ([class.virtual]), могут вызываться во время создания или уничтожения ([class.base.init]).

(Ваш конструктор начал выполнение.)

Но есть еще это специально для деструкторов:

Как только деструкторвызывается для объекта, объект больше не существует;поведение не определено, если деструктор вызывается для объекта, срок жизни которого истек ([basic.life]). [Пример: Если деструктор для автоматического объекта вызывается явным образом, а затем блок оставляется таким образом, который обычно вызывает неявное уничтожение объекта, поведение не определено. - конец примера]

Итак, хотя мы знаем, что ваш деструктор не будет вызываться неявно «снова», вопрос в том, приведет ли последующее повторное выбрасывание к сценарию, в которомобъект «снова» разрушен в смысле, описанном в этом отрывке.

Я на самом деле разочаровался в стандарте в этой точке, и мне интересно, немного ли это занижено.Я хочу сказать, что это само по себе является, вероятно, достаточной причиной, чтобы избежать этого благонамеренного паттерна, и просто вместо этого поместите свою очистку в симпатичную приватную функцию-член для совместного использования между вашим блоком catch и вашим деструктором.

...