В C ++ вы можете указать, что функция может или не может генерировать исключение, используя спецификатор исключения. Например:
void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type
Я сомневаюсь в том, чтобы использовать их на самом деле по следующим причинам:
- Компилятор на самом деле не применяет спецификаторы исключений каким-либо строгим образом, поэтому преимущества невелики. В идеале вы хотели бы получить ошибку компиляции.
- Если функция нарушает спецификатор исключения, я думаю, что стандартным поведением является завершение программы.
- В VS.Net он обрабатывает throw (X) как throw (...), поэтому соблюдение стандарта не является строгим.
Как вы думаете, следует ли использовать спецификаторы исключений?
Пожалуйста, ответьте «да» или «нет» и укажите причины, чтобы обосновать свой ответ.
Ответы:
Нет.
Вот несколько примеров, почему:
Код шаблона невозможно написать с указанием исключений,
Копии могут генерироваться, передача параметров может генерироваться и
x()
может вызывать какое-то неизвестное исключение.Спецификации исключений обычно запрещают расширяемость.
может превратиться в
Вы действительно могли бы написать это как
Первое не расширяемо, второе слишком амбициозно, а третье действительно то, что вы имеете в виду, когда пишете виртуальные функции.
Устаревший код
Когда вы пишете код, основанный на другой библиотеке, вы действительно не знаете, что он может делать, если что-то пойдет не так.
g
прекратится, когдаlib_f()
бросит. Это (в большинстве случаев) не то, что вам действительно нужно.std::terminate()
никогда не должен называться. Всегда лучше позволить приложению аварийно завершить работу с необработанным исключением, из которого вы можете получить трассировку стека, чем молча / насильственно умереть.Напишите код, который возвращает общие ошибки и выдает в исключительных случаях.
Тем не менее, когда ваша библиотека просто генерирует ваши собственные исключения, вы можете использовать спецификации исключений, чтобы заявить о своем намерении.
источник
try {...} catch (<specified exceptions>) { <do whatever> } catch (...) { unexpected(); ]
конструкцию, независимо от того, хотите ли вы там блок try или нет.try { <<...code...>> } catch(...) /* stack guaranteed to be unwound here and dtors run */ { throw; /* pass it on to the runtime */ }
terminate()
? Почему бы просто не позвонитьabort()
?Избегайте спецификаций исключений в C ++. Причины, по которым вы задаете свой вопрос, являются хорошим началом для объяснения причин.
См. «Прагматичный взгляд на спецификации исключений» Херба Саттера .
источник
throw(optional-type-id-list)
) не рекомендуется в C ++ 11. Они все еще находятся в стандарте, но я думаю, что было отправлено предупреждение, что их использование следует тщательно продумать. C ++ 11 добавляетnoexcept
спецификацию и оператор. Я не знаю достаточно подробностей,noexcept
чтобы прокомментировать это. Эта статья выглядит довольно подробной: akrzemi1.wordpress.com/2011/06/10/using-noexcept И у Дитмара Кюля есть статья в июньском журнале перегрузки 2011 года: accu.org/var/uploads/journals/overload103.pdfthrow(something)
считается бесполезным и плохой идеей.throw()
является полезным.Я думаю, что стандартное исключение (для C ++)
спецификаторов исключений было экспериментом в стандарте C ++, который в основном провалился.
Исключением является то, что спецификатор no throw полезен, но вы также должны добавить соответствующий блок try catch внутри, чтобы убедиться, что код соответствует спецификатору. У Херба Саттера есть страница по этой теме. Gotch 82
В дополнение, я думаю, стоит описать гарантии исключений.
В основном это документация о том, как на состояние объекта влияют исключения, экранирующие метод этого объекта. К сожалению, компилятор не применяет их и не упоминает иным образом.
Повышение и исключения
Гарантии исключения
Без гарантии:
Основная гарантия:
Сильная гарантия: (также известная как транзакционная гарантия)
Гарантия отсутствия броска:
источник
Guarantee that functions will only throw listed exceptions (possibly none)
. Не правда. Это только гарантирует, что если функция выдаст эти исключения, приложение завершит работу.Enable compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown
Не могу этого сделать. Поскольку я только что указал, вы не можете гарантировать, что исключение не будет создано.throw()
(не генерирует). « Это только гарантирует, что если функция вызовет эти исключения, приложение завершит работу. « Нет »не верно» означает «истина». В C ++ нет гарантии, что функцияterminate()
никогда не будет вызвана. « Поскольку я только что указал, вы не можете гарантировать, что исключение не будет сгенерировано». Вы гарантируете, что функция не сгенерирует. Это именно то, что вам нужно.gcc выдаст предупреждения, если вы нарушите спецификации исключения. Что я делаю, так это использую макросы для использования спецификаций исключений только в режиме компиляции "lint" специально для проверки, чтобы убедиться, что исключения согласуются с моей документацией.
источник
Единственный полезный спецификатор исключения - это «throw ()», как в «не выбрасывает».
источник
Спецификации исключений - не очень полезные инструменты в C ++. Однако для них / есть / хорошее применение в сочетании с std :: неожиданно.
В некоторых проектах я использую код со спецификациями исключений, а затем вызываю set_unexpected () с функцией, которая генерирует специальное исключение моего собственного дизайна. Это исключение при построении получает обратную трассировку (в зависимости от платформы) и выводится из std :: bad_exception (чтобы разрешить его распространение при желании). Если это вызывает вызов terminate (), как это обычно бывает, обратная трассировка печатается с помощью what () (а также исходное исключение, которое его вызвало; это не сложно найти), и поэтому я получаю информацию о том, где был мой контракт нарушено, например, возникло непредвиденное исключение библиотеки.
Если я сделаю это, я никогда не разрешаю распространение исключений библиотеки (кроме std) и получаю все свои исключения из std :: exception. Если библиотека решит бросить, я поймаю и конвертирую в свою собственную иерархию, что позволит мне всегда контролировать код. Шаблонные функции, вызывающие зависимые функции, должны избегать спецификаций исключений по очевидным причинам; но в любом случае редко бывает шаблонный интерфейс функции с кодом библиотеки (и несколько библиотек действительно используют шаблоны полезным образом).
источник
Если вы пишете код, который будет использоваться людьми, которые предпочли бы смотреть на объявление функции, чем на какие-либо комментарии к нему, тогда спецификация сообщит им, какие исключения они могут захотеть перехватить.
В противном случае я не считаю особенно полезным использовать что-либо, кроме
throw()
как указать, что это не вызывает никаких исключений.источник
Нет. Если вы используете их, и возникает исключение, которое вы не указали, либо вашим кодом, либо кодом, вызванным вашим кодом, то поведение по умолчанию - незамедлительно завершить вашу программу.
Кроме того, я считаю, что их использование устарело в текущих проектах стандарта C ++ 0x.
источник
Спецификация throw () позволяет компилятору выполнять некоторые оптимизации при анализе потока кода, если он знает, что функция никогда не вызовет исключение (или, по крайней мере, обещает никогда не генерировать исключение). Ларри Остерман вкратце рассказывает об этом здесь:
http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx
источник
Обычно я бы не использовал спецификаторы исключений. Однако в случаях, когда из рассматриваемой функции должно исходить какое-либо другое исключение, которое программа окончательно не сможет исправить , это может быть полезно. Во всех случаях обязательно четко документируйте, каких исключений можно ожидать от этой функции.
Да, ожидаемым поведением неуказанного исключения, генерируемого функцией со спецификаторами исключения, является вызов terminate ().
Замечу также, что Скотт Мейерс рассматривает эту тему в «Более эффективном C ++». Его книги «Эффективный C ++» и «Более эффективный C ++» очень рекомендуются.
источник
Да, если вам нужна внутренняя документация. Или, может быть, написать библиотеку, которую будут использовать другие, чтобы они могли знать, что происходит, не обращаясь к документации. Бросок или не бросание можно рассматривать как часть API, почти как возвращаемое значение.
Я согласен, они не очень полезны для обеспечения корректности стиля Java в компиляторе, но это лучше, чем ничего или случайные комментарии.
источник
Они могут быть полезны для модульного тестирования, чтобы при написании тестов вы знали, чего ожидать от функции, когда она терпит неудачу, но в компиляторе их не применяют. Я думаю, что это лишний код, который не нужен в C ++. Что бы вы ни выбрали, все, в чем вы должны быть уверены, так это в том, что вы следуете одному и тому же стандарту кодирования для всего проекта и членов команды, чтобы ваш код оставался читаемым.
источник
Из статьи:
http://www.boost.org/community/exception_safety.html
И действительно, я могу придумать способы сделать исключения шаблонных классов безопасными. Если у вас нет контроля над всеми подклассами, у вас все равно может возникнуть проблема. Для этого можно создать в своих классах определения типов, которые определяют исключения, создаваемые различными классами шаблонов. Я думаю, что проблема, как всегда, в том, чтобы решать ее потом, а не проектировать ее с самого начала, и я думаю, что именно эти накладные расходы являются настоящим препятствием.
источник
Спецификации исключения = мусор, спросите любого Java-разработчика старше 30 лет.
источник