Использование только std :: exception в спецификации исключения

Похоже, общепринято, что спецификации исключений не помогают так сильно, как кажется. Но мне интересно, может ли спецификация, в которой используется только std :: exception, быть хорошим компромиссом:

void someFunction()
    throw ( std::exception );
  • Он документирует тот факт, что этот метод / функция может вызвать исключение.

  • Это гарантирует, что генерируются только исключения, производные от std :: exception, а не некоторые экзотические классы, такие как std :: string или int.

Так что лучше, чем вообще не иметь спецификации?

Обновлять:

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

#ifdef DEBUG
    #define THROW( exception ) throw ( exception )
#else
    #define THROW( exception )
#endif

void someFunction()
    THROW( std::exception );

Нет, это ни в чем не гарантирует. Это проблема. Вы обещаете, что больше ничего не будет брошено, вы не просите компилятор проверить, что это действительно так.

jalf 04.12.2008 20:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
2 748
4

Ответы 4

В соответствующем компиляторе добавление непустой спецификации исключения генерирует эквивалент блока try / catch вокруг функции. Хотя это можно реализовать без дополнительных затрат времени выполнения, в некоторых текущих компиляторах накладные расходы действительно возникают.

Таким образом, это может быть связано с затратами, и все, что вы получаете, это то, что если someFunction или что-то, что он вызывает, вызывает исключение, не производное от std::exception, вызывается std::unexpected, а не механизм необработанных исключений.

Думаю, мой ответ - «Нет» :-)

Добавление блока try / catch практически не требует затрат (при отсутствии распространения исключений) в современных компиляторах, так что это вызывает беспокойство.

Martin York 04.12.2008 20:23

Я изменю свою формулировку - «самые современные компиляторы» были неправильными. Но если вы компилируете для 32-разрядной версии с помощью Visual Studio, это все равно нужно учитывать.

James Hopkin 04.12.2008 20:44

Хм, я только что заметил другой ответ, в котором говорится, что VC++ полностью игнорирует спецификацию исключений, и я думаю, что это может быть правильно. Ну да ладно ... это все еще плохая идея :-)

James Hopkin 04.12.2008 20:51

На самом деле MSVC уважает метод nothrow (или, скорее, использует его как подсказку по оптимизации), но игнорирует все другие спецификации и никогда не вызывает std :: неожиданный.

jalf 04.12.2008 21:42

Да, но что вы ожидаете, когда возникает что-то, что не является производным от std :: exception?

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

Разница между спецификациями исключений Java и C++ заключается в том, что Java проверяет спецификации во время компиляции. C++, с другой стороны, выполняет все проверки во время выполнения. Так что к тому времени, когда ваши требования будут нарушены, будет уже слишком поздно.

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

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

Также прочтите Статья Херба Саттерса:

И эта ветка на SO: Следует ли использовать спецификатор исключения в C++?

Хорошее объяснение проблем со спецификациями, проверенными во время компиляции. Я обсуждал это несколько раз за эти годы ...

James Hopkin 04.12.2008 20:49

@Martin York: обратите внимание, что совет Херба Саттера - НЕ использовать даже пустую спецификацию исключения. См. gotw.ca/publications/mill22.htm

paercebal 06.12.2008 02:57

Спецификации исключений по сути бесполезны. Мартин Йорк уже ссылался на пост Херба Саттера о них, но вкратце вы сталкиваетесь со следующими проблемами:

  1. Они игнорируются MSVC, и
  2. Их эффект не похож на Ява. Технические характеристики проверены во время выполнения, вызывая производительность ударил, не давая тебе проверка во время компиляции, которую вы получаете Ява. Все, что вы говорите, это "Вставьте дополнительный код, чтобы, когда генерируется исключение, проверяется его тип, а затем либо кидай как обычно, либо звони неожиданный () вместо этого.

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

Мир не вращается вокруг MSVC ;-), и я не понимаю, как было бы сложнее поймать выброшенное исключение, поскольку единственное, что он предотвращает, - это генерировать какое-то произвольное исключение, а не исключение на основе std :: exception.

user31157 05.12.2008 12:21

ПРОЧИТАЙТЕ сообщение Саттерса! Они НЕ предотвращают создание произвольных исключений. Они только предотвращают НАХОЖДЕНИЕ произвольных исключений - главное отличие.

MSalters 05.12.2008 15:19

Я прочитал сообщение. Я могу согласиться с тем, что, строго говоря, они НЕ ПРЕДОТВРАЩАЮТ произвольных исключений. Но поскольку программа будет прервана (если вы создадите другое исключение и не настроили обработчик ошибок с помощью set_unexpected), она очень похожа на assert.

user31157 05.12.2008 16:12

Я бы сделал это типично:

void someFunction() /* throw (std::exception) */;

Единственный эффект оператора throw в объявлении функции - изменить ее сигнатуру: указатель на «void x ()» и указатель на «void x () throw y» - это два разных типа. Таким образом, вы все еще документируете, что функция может что-то выбросить, и вы ничего не теряете, поскольку компилятор C++ в любом случае не применяет никаких ограничений.

Другие вопросы по теме