Почему исключения в C ++ не проверяются компилятором? - PullRequest
40 голосов
/ 24 июня 2009

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

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

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

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

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

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

Ответы [ 6 ]

38 голосов
/ 26 июня 2009

Что забавно, так это то, что 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!
}

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

30 голосов
/ 24 июня 2009

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

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

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

15 голосов
/ 24 июня 2009

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

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

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

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

9 голосов
/ 24 июня 2009

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

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

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

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

от Gimpel Software.

1560 Не найденное исключение «Имя» отсутствует в списке бросков для функции «Символ»

и, согласно этого ответа на предыдущий вопрос, QA C ++ .

8 голосов
/ 24 июня 2009

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

0 голосов
/ 24 июня 2009

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

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

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

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