Должен ли я поместить блок try ... catch в деструктор, если я знаю, что моя функция не выдаст исключение - PullRequest
3 голосов
/ 07 декабря 2009

Я знаю, что деструктор не должен выбрасывать исключение.

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.13

У меня есть следующий код:

~a()
{
    cleanup();
}

// I do not expect exception being thrown in this function.
// If exception really happen, I know that it is something not recoverable.
void a::cleaup()
{
    delete p;
}

В моем статическом анализе исходного кода он жалуется, что я вызову функцию очистки следующим образом:

~a()
{
    try {
        cleanup();
    }
    catch(...) {
        // What to do? Print out some logging message?
    }
}

// I do not expect exception being thrown in this function.
// If exception really happen, I know that it is something not recoverable.
void a::cleaup()
{
    delete p;
}

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

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

(2) Накладные расходы возникают при входе и выходе из блока try ... catch.

(3) Код выглядит громоздким, с большим количеством попыток ... ловить блок вокруг деструктора классов.

Я могу пропустить некоторые другие моменты, зачем пытаться ... блок catch должен быть на месте.

Спасибо.

Ответы [ 6 ]

3 голосов
/ 07 декабря 2009

Поскольку delete не выбрасывает, не будет cleanup, и поэтому нет необходимости помещать вызов в try-catch.

Поскольку вашему инструменту статического анализа, вероятно, трудно понять это, возможно, вы могли бы помочь (хотя это только предположение), объявив cleanup как безбросок.

void cleanup() throw();
2 голосов
/ 07 декабря 2009

Может быть, вы можете быть более точным о вашей функции очистки. Функция cleanup () генерирует исключение преднамеренно, хотя бы в очень редких случаях? Тогда вам определенно следует обработать регистр в вашем деструкторе, потому что, даже если это редкое явление, выдается исключение, ожидаемое поведение cleanup ().

По крайней мере, ваш код обработки исключений может оставить вашу программу в четко определенном состоянии, что позволит вам аккуратно завершить ее.

Или вы имеете в виду, что cleanup () может выдать, например, OutOfMemoryException или другое исключение во время выполнения, которое вы никогда не обрабатывали где-либо еще? Тогда я бы опустил обработку исключений и в деструкторе. В таких необычных обстоятельствах ваше приложение, возможно, в любом случае не сможет запустить свой код обработки ошибок. Вы должны сделать все возможное, чтобы убедиться, что даже такие исключения регистрируются или регистрируются должным образом.

Редактировать:

Теперь, когда вы показали реализацию cleanup, Нил уже ответил на ваш вопрос. delete p не должен бросать, следовательно, a::cleanup не будет бросать, пока деструктор p не бросит.

1 голос
/ 07 декабря 2009

Обычно нет смысла выдавать ошибку из-за выделения или удаления памяти. Это либо работает, либо нет, и вы можете потратить массу усилий на обработку глупых ошибок, не получая никакой выгоды.

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

1 голос
/ 07 декабря 2009

По сути, генерировать исключение небезопасно, пока уже обрабатывает исключение.

Если ваш деструктор вызывается, пока стек разматывается, и выдается другое исключение, тогда ваш поток может быть немедленно прерван в некоторых системах, таких как Symbian; то, что ваш код планировал перехватить исключение, не остановит это завершение - ваш код даже не будет вызван. Ваш поток наверняка будет прерван, если ваше исключение ускользнет от деструктора .

Так что try {} catch(...) {} в деструкторе не является переносимым и, конечно, хитро.

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

Оригинальный постер также запрашивает производительность try-catch. В начале принятия исключений C ++ код обработки исключений был достаточно дорогим; в наши дни ваш компилятор почти наверняка использует исключения с нулевой стоимостью, что означает, что исключение, которое не было сгенерировано, не добавляет никакого снижения производительности во время выполнения кода (но, конечно, немного увеличивает двоичный размер программы).

1 голос
/ 07 декабря 2009

Конечно, проблема действительно в деструкторе p. Когда в cleanup () вы говорите

delete p;

Само удаление не может выдать, поэтому исключение должно исходить от деструктора p. Именно в этом деструкторе вам нужно беспокоиться об использовании блока try, а не блока a.

0 голосов
/ 07 декабря 2009

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

Однако, функция cleanup не должна бросать в первую очередь. Поэтому я бы поместил любую обработку исключений в cleanup(), а не в сам деструктор.

...