Блок Try / Catch заменяет блок метода в деструкторе - PullRequest
6 голосов
/ 10 мая 2011

Недавно мне было поручено отыскать утечку памяти в части нашего кода.Утечка оказалась в деструкторе для определенного объекта ... и я нашел что-то действительно странное.Бывший сотрудник написал это:

File::~File()
try
{
    Clear();
}
catch (...)
{
    Log("caught exception");
}

Класс файла наследуется от некоторых базовых классов.Мой первый вопрос: это строго законный C ++?Он компилируется в Visual Studio 2008, но я показал его нескольким друзьям / коллегам, и они были в ужасе от того, что это сработало.

На самом деле он работает не так, как задумано: базовый класс, от которого наследуется этот объект, имеет деструктор, который теперь никогда не вызывается (в отличие от того, если вы просто обернули деструктор в обычный блок методаtry / catch как часть этого метода).

Может кто-нибудь попытаться объяснить, почему это разрешено и почему не был вызван деструктор базового класса?Деструктор здесь не бросал.

Ответы [ 2 ]

10 голосов
/ 10 мая 2011

Это функциональный блок try, и он полностью допустим.

См., Например, здесь .

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

Этот GOTW # 66 особенно интересен, хотя в нем больше внимания уделяется конструкторам. Он содержит эту «мораль»:

Поскольку деструкторы никогда не должны генерировать исключение, функциональные блоки-деструкторы вообще не имеют практического применения.

Просто чтобы добавить пояснение, код в том виде, в котором он написан, приведет к тому, что любое пойманное исключение будет переброшено из-за ИСО / МЭК 14882: 2003 15.3 [кроме. Handle] / 16:

Обрабатываемое исключение перебрасывается, если управление достигает конца обработчика function-try-block конструктора или деструктора. [...]

Однако допустимо, чтобы в обработчике блока try функции для деструктора был установлен return без параметров - он запрещен только в блоке try функции для конструктора - и это подавит повторное исключение исключения. Поэтому любая из этих альтернатив не позволит исключению покинуть деструктор.

File::~File()
try
{
    Clear();
}
catch (...)
{
    Log("caught exception");
    return;
}

File::~File()
{
    try
    {
        Clear();
    }
    catch (...)
    {
        Log("caught exception");
    }
}
4 голосов
/ 10 мая 2011

Чтобы ответить на вторую часть, «почему деструктор базового класса не был вызван?», 12.4 / 6:

После выполнения тела деструктора и уничтожения любых автоматических объектов, размещенных в теледеструктор для класса X вызывает деструкторы для прямых членов X, деструкторы для прямых базовых классов X ... Оператор return (6.6.3) в деструкторе не может напрямую возвращаться вызывающей стороне;перед передачей управления вызывающей стороне деструкторы для членов и баз вызываются.

Это не говорит о том, что деструкторы-члены и базы вызываются, если деструктор выбрасывает.Однако в 15.2 / 2 говорится:

Для объекта, который частично построен или частично уничтожен, будут выполняться деструкторы для всех полностью построенных подобъектов,

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

Однако, очевидно, Microsoft не согласна, и из-за блока try функции, который она не сгенерировала »тело деструктора ", и не сделал того, что происходит после выполнения" тела деструктора ".

Это не звучит мне правильно.GCC 4.3.4 выполняет деструктор базового класса, независимо от того, выполняет ли функция производного класса dtor блок try или нет.В случае, когда он выбрасывает, база уничтожается до выполнения предложения catch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...