Почему исключения в С++ не проверяются компилятором?

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

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

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

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

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

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

Ответ 1

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

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

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

Ответ 2

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

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

1. Спецификации исключений на языке С++ запрещают оптимизацию.

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

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

Что касается вашего компилятора, то синтаксически корректно следующее:

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

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

3. Спецификации исключений С++ являются частью сигнатуры функции.

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

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

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

Ответ 6

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

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

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