Возражение против исключений - PullRequest
8 голосов
/ 11 февраля 2011

Один из моих друзей поднял эту проблему для меня. Я застрял, потому что я не знаток использования исключений. Имейте в виду, что мы оба работаем в рабочей среде, где мы используем C ++, но делаем обработку ошибок в традиции C. Его проблема была примерно такой:

Функция A вызывает B, что в свою очередь вызывает C. Из C выдается исключение, и блок catch для этого исключения находится в A. Что происходит с ресурсами, приобретенными в B до вызова C? Как мы их уберем? Мой ответ был использовать RAII. Но даже когда я это сказал, я знал, что это не сработает. У нас есть огромные базы кода, которые были написаны в режиме C. Нигде в коде я не видел авто указатели и тому подобное. Ресурсы не обязательно заключены в классы. Даже когда они есть, деструкторы оставляются для компилятора в большинстве случаев. Одним словом, все делается вручную.

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

Ответы [ 7 ]

5 голосов
/ 11 февраля 2011

Существует методика, разработанная Андреем Александреску и Джошуа Лерером, под названием Scope Guard , которая предоставляет технику для предоставления кода «выхода из области действия», как только вы выделяете объект, и открывания области действия для него. в этот момент.

Язык программирования D фактически имеет стандарт.

В

boost библиотеки есть расширение, называемое Scope Exit . Если ваш код не является безопасным для исключений, так как функция B, по-видимому, не является таковой, он не будет обрабатываться должным образом, если что-то сработает.

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

2 голосов
/ 11 февраля 2011

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

Нет, реальная проблема в том, что, поскольку вы программируете на C ++, вам давно уже покончено с этим. Даже если ваш собственный код не генерирует исключения, некоторый код в стандартной библиотеки и системы времени выполнения может выдавать (new, dynamic_cast) и, конечно, любой третий Программное обеспечение, которое вы используете, может быть хорошо.

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

1 голос
/ 11 февраля 2011

C ++ Не поддерживает finally для управления последними вещами в конце блока.

Что произойдет, если функция C сгенерирует исключение, она вернется из функции. Это означает, что все локальные переменные будут уничтожены.
Затем программа вернется к коду в B , проверит наличие блока перехвата, увидит, что его нет, и вернется к функции A. И снова все локальные переменные в B будут освобождены.

Вы должны помнить, что вы работаете в C ++ .... Вы должны управлять своими объектами. Так что если у вас есть объекты, которые просто интересуются свободно в B (с указателями или чем-то еще), то это плохой дизайн кода, и они не будут выпущены.

Если в B вы знаете, что в C может быть исключение, вы можете просто поставить там ловушку и затем отбросить пойманную исключительную ситуацию.

Ближайший к блоку finally вы можете использовать catch(...) и использовать его для освобождения памяти ... но он будет введен, только если действительно было исключение, поэтому он не идентичен finally

try {

}
catch(...) {
  // free stuff affected by an exception here
}

Если вы хотите работать точно так же, как блок finally, вы можете сделать:

try {
   //Do stuff
   goto finally
}
catch(...) {
  finally:
  // free stuff affected by an exception here
}

Для всех вас, у которых есть проблема с goto ... это по-прежнему команда, и это прекрасный пример того, что ни break, ни continue, ни какая-либо встроенная функция не может заменить goto.

Еще немного о Перейти

1 голос
/ 11 февраля 2011

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

0 голосов
/ 11 февраля 2011

Радуйтесь, что у вас есть исключения. Посмотрите, что происходит с кодами возврата ошибок в вашем примере. Функция C возвращает код ошибки. B, будучи наивным как есть, глотает его. Вызывающий A, который мог бы справиться с этим, даже не проинформирован об ошибке.

Лучше всего перейти с C прямо на C ++ 0x. Он предлагает новую функцию, лямбда. Это анонимные функции, определенные в других функциях. Вы можете поместить туда свой код очистки C и вызвать его с помощью объекта scopeguard. Пример (я бы пропустил макрос)

0 голосов
/ 11 февраля 2011

Выдержка из моей заброшенной домашней страницы ...

Не повторяя в деталях все проблемы, присущие исключению обработка (1) Я хочу отметить только Основная идея: сложная часть не где генерируется исключение (бросить) или где исключение обрабатывается (ловить) но в методах все классы исключение проходит почти асинхронно во время процесс разматывания стека.

Обращая внимание на то, как методы написано относительно легко избежать потеря ресурсов в случае исключений (использование auto_ptr и подобных классов) но все гораздо сложнее, когда учитывается логическое состояние объекта или других объектов манипулировали перед броском. в самое строгое значение исключительной безопасности метод должен либо успешно или будучи неоператором: другими словами логическое состояние объекта называется (и другие задействованные объекты) должны быть то же самое, если выдается исключение: нет разница должна быть видна через общедоступный интерфейс всех участников классы.

...

(1) Для подробного описания прочитайте статья «Обработка исключений: ложь Чувство безопасности "Том Каргилл доступно онлайн или интересное коллекция проблем / решений, которые эта статья создана в USENET доступно по книге "Исключительно С ++ "от Херба Саттера ISBN 0-201-61562-2 =.

0 голосов
/ 11 февраля 2011

Ваш друг абсолютно прав, и это одна из причин того, что Google не использует исключения внутри страны. См. http://google -styleguide.googlecode.com / svn / trunk / cppguide.xml # Исключения (и откройте маленькую стрелку) для объяснения проблемы.

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