2009-06-24 6 views
36

C++ предоставляет синтаксис для проверяемых исключений, например:Почему исключения в C++ не проверяются компилятором?

void G() throw(Exception); 
void f() throw(); 

Однако Visual C++ компилятор не проверяет их; флаг throw просто игнорируется. По моему мнению, это исключает возможность использования исключения. Так что мой вопрос: есть ли способ заставить компилятор проверить, правильно ли пойманы или восстановлены исключения? Например, плагин Visual C++ или другой компилятор C++.

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

Обновление: Компилятор Visual C++ показывает предупреждение при бросании функции, помеченной throw(). Это здорово, но, к сожалению, предупреждение не появляется, когда вы вызываете подпрограмму, которая может быть брошена. Например:

void f() throw(int) { throw int(13); } 
void h() throw() { g(); } //no warning here! 
+0

Я никогда не слышал об проверенных исключениях на C++, но теперь я расскажу об исключении спецификации и что Visual C++ не очень-то о них беспокоит, посмотрите здесь: http://msdn.microsoft.com/ en-us/library/wfa0edys.aspx – Skurmedel

+1

Visual C++ не совсем игнорирует это ... добавление throw() в конец функции сообщает Visual C++, что он может предположить, что функция не выбрасывает, например оптимизации, и если функция действительно бросает, то все может случиться. В стандарте говорится, что если функция отмечена throw() выходит из-за исключения, то std :: неожиданный(), который обычно генерирует std :: bad_exception.Это очень отличается от того, что «может случиться». – Doug

+0

Если спецификации исключений были подсказками для компиляторов, а не требованиями для чего-то, они были бы потенциально полезными. Стандартное поведение, на мой взгляд, бесполезно. –

ответ

29

Спецификации исключения в C++ довольно бесполезны.

Это не применяются никакие другие исключения не будут выброшены, а лишь о том, что глобальная функция unexpected() будет называться (который может быть установлен)

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

+0

«Невозможно» - довольно сильное требование. Почему принудительное исключение спецификаций исключений невозможно с помощью шаблонов? –

+0

думая об этом, вы правы, конечно, не знаете, где я получил это, удалил абзац – Pieter

+1

Правильное настроение, но совершенно неправильный аргумент. C++ (в отличие от Java и большинства других современных языков) проверяет спецификацию исключений во время выполнения, а не время компиляции. К сожалению, этот эксперимент в спецификациях исключений не работал (кроме броска). –

14

Посмотрите на это:

http://www.gotw.ca/publications/mill22.htm

в основном спецификация исключений являются непригодными/непригодным для использования, но это не делает исключение неработоспособным.

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

+1

Спасибо за ваш ответ. Проблема с catch (...) на верхнем уровне заключается в том, что на C++ вы почти не получаете информации о том, что произошло: нет информации о типе и стека вызовов. Эту проблему можно обойти, исключив один тип исключений очень дисциплинированным способом, но это вызывает склонность к ошибкам. –

+1

@ Dimitri: Я бы не согласился, всегда бросаю исключения, полученные из std :: exception, нет необходимости в большой дисциплине, чтобы это сделать ... – Patrick

0

Я не могу проверить это из-за отсутствия установки MSVC, но действительно ли вы уверены, что компилятор игнорирует спецификацию throw()?

This MSDN page предполагает, что Microsoft знает о throw() и ожидает, что их компилятор обработает его правильно. Ну, почти, см. Примечание о том, как они отходят от стандарта ANSI/ISO в некоторых деталях.

Редактировать: На практике, однако, я согласен с Патриком: спецификации исключений в основном бесполезны.

8

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

9

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

extern void f() throw (class Mystery); 
void g() throw() { 
    f() ; 
} 

... Вам нужно статический анализ. Да, компилятор делает много статического анализа, но поскольку стандарт «raise std :: неожиданный, если бросок не соответствует», и вполне законно писать процедуру, которая бросает объект, который не соответствует спецификатору , разработчики компилятора не предупреждают и не замечают.

инструменты статического анализа, которые утверждают, что для обеспечения предупреждения услуги включают Gimpel Software, lint for C++ ...

1560 Uncaught исключение 'Name' не на вбрасывание список для функции 'Символ'

и, согласно this answer по предыдущему вопросу, QA C++.

37

Забавно, что Java проверяет исключения, и Java-программисты тоже ненавидят их.

спецификации исключений в C++ бесполезны по 3 причинам:

1. C++ спецификации исключений ингибируют оптимизацию.

За исключением, возможно, throw(), компиляторы вставляют дополнительный код, чтобы проверить, что, когда вы генерируете исключение, оно соответствует спецификации исключения функций во время стека. Способ сделать вашу программу медленнее.

2. C++ спецификации исключений не компиляторы

Насколько ваш компилятор обеспокоен, следующий синтаксически корректен:

void AStupidFunction() throw() 
{ 
    throw 42; 
} 

Что еще хуже, ничего полезного не произойдет, если вы нарушаете спецификация исключения. Ваша программа просто заканчивается!

3. Спецификации исключений C++ являются частью подписи функции.

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

struct A 
{ 
    virtual int value() const throw() {return 10;} 
} 

struct B : public A 
{ 
    virtual int value() const {return functionThatCanThrow();} // ERROR! 
} 

Спецификации исключений дают вам эти проблемы, а коэффициент их использования минимален. Напротив, если вы вообще избегаете спецификаций исключений, кодирование проще, и вы избегаете этого.

+0

Хороший ответ! Благодарю. –

+0

мы можем работать «бросить 42;» вопрос? – Anuj

Смежные вопросы