Киньте ключевое слово в подпись функции

По какой технической причине использование C ++ считается плохой практикоthrow ключевое слово в сигнатуре функции?

<code>bool some_func() throw(myExc)
{
  ...
  if (problem_occurred) 
  {
    throw myExc("problem occurred");
  }
  ...
}
</code>
 laalto28 июн. 2009 г., 20:10
См. Этот недавний связанный вопрос: / Stackoverflow.com вопросы / 1037575 / ...
 François Andrieux05 апр. 2018 г., 20:37
Следует отметить исключения спецификации устарела с C ++ 11.
 akauppi11 сент. 2009 г., 13:05
 Aaron McDaid18 авг. 2015 г., 14:08
Делаетnoexcept изменить что-нибудь?
 Anders Lindén28 мар. 2016 г., 12:58
Нет ничего плохого в том, чтобы иметь мнение о том, что связано с программированием. Этот закрывающий критерий плох, по крайней мере, для этого вопроса. Это интересный вопрос с интересными ответами.

Ответы на вопрос(7)

м, что если что-то отличается отmyExc выбрасывается твоей функцией,std::unexpectedудет вызываться @ (вместо обычного механизма необработанного исключения).

Для документирования исключений, которые может генерировать функция, я обычно делаю это:

bool
some_func() /* throw (myExc) */ {
}
 jalf28 июн. 2009 г., 21:14
- и что MSVC, по крайней мере, не реализует это поведение, насколько я знаю.
 sth28 июн. 2009 г., 20:28
Также полезно отметить, что вызов std :: непредвиденный () обычно приводит к вызову std :: terminate () и неожиданному завершению вашей программы.
Решение Вопроса

это не считается хорошей практикой. Наоборот, это вообще считается плохой идеей.

http: //www.gotw.ca/publications/mill22.ht объясняет почему, но проблема отчасти в том, что компилятор не может принудительно это реализовать, поэтому его нужно проверять во время выполнения, что обычно нежелательно. И это не очень хорошо поддерживается в любом случае. (MSVC игнорирует спецификации исключений, кроме throw (), что интерпретируется как гарантия того, что исключение не будет выдано.

 jalf28 июн. 2009 г., 23:23
yeah, люди, которые просто обнаруживают спецификации исключений, часто предполагают, что они работают как в Java, где компилятор может применять их. В C ++ этого не произойдет, что делает их намного менее полезными.
 Rob Kennedy28 июн. 2009 г., 22:48
Дело не в том, чтобы не применять его во время компиляции. В конце концов, Java-компиляторы могут применять его. Дело в том, что он не должен применяться во время компиляции. Функция полностью может генерировать другие исключения, но если это так, то должна вызываться непредвиденная ().
 Assaf Lavie28 июн. 2009 г., 20:36
Да. Есть лучшие способы добавить пробел к вашему коду, чем throw (myEx).
 Anders Lindén28 мар. 2016 г., 13:03
Но как насчет документации? Кроме того, вам сообщат, какие исключения вы никогда не поймаете, даже если попытаетесь.
 Anders Lindén01 апр. 2016 г., 12:14
Я думаю, что код эффективен для документирования вашего кода. (комментарии могут врать). «Документативный» эффект, о котором я говорю, заключается в том, что вы будете точно знать, какие исключения вы можете поймать, а какие нет.

которая возвращает только переменную-член и не может генерировать исключения, может использоваться некоторыми компиляторами для пессимизации (в противоположность оптимизации), которая может отрицательно сказаться на производительности. Это описано в литературе Boost: Exception-спецификация

С некоторые компиляторы Спецификация no throw для не встроенных функций может быть полезной, если выполнены правильные оптимизации и использование этой функции влияет на производительность так, как это оправдывает ее.

Для меня это звучит так: использовать это или нет - это вызов, сделанный очень критическим взглядом как часть усилий по оптимизации производительности, возможно, с использованием инструментов профилирования.

Цитата из приведенной выше ссылки для спешащих:

Обоснование спецификации исключения

Спецификации исключений [ISO 15.4] иногда кодируются, чтобы указать, какие исключения могут быть сгенерированы, или потому, что программист надеется, что они улучшат производительность. Но рассмотрим следующий член из умного указателя:

T & operator * () const throw () {return * ptr; }

Эта функция не вызывает никаких других функций; он манипулирует только базовыми типами данных, такими как указатели. Поэтому никогда нельзя вызывать поведение спецификации исключений во время выполнения. Функция полностью доступна для компилятора; на самом деле он объявлен как встроенный. Следовательно, умный компилятор может легко определить, что функции не способны генерировать исключения, и выполнить те же оптимизации, что и на основе пустой спецификации исключений. Однако «тупой» компилятор может создавать различные пессимизаци

Например, некоторые компиляторы отключают встраивание, если есть спецификация исключения. Некоторые компиляторы добавляют блоки try / catch. Такая пессимизация может привести к снижению производительности, что делает код непригодным для практического применения.

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

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

Jalf уже связан с ним, но GOTW очень хорошо объясняет, почему спецификации исключений не так полезны, как можно было бы надеяться:

int Gunc() throw();    // will throw nothing (?)
int Hunc() throw(A,B); // can only throw A or B (?)

Правильны ли комментарии? Не совсем.Gunc() действительно может что-то бросить, аHunc() вполне может бросить что-то кроме A или B! Компилятор просто гарантирует, что побеждать их будет бессмысленно, если они это сделают ... и большую часть времени бить вашу программу тоже бессмысленно.

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

Вывод GOTWs:

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

Мораль №1: Никогда не пишите спецификацию исключений. Мораль № 2: За исключением, возможно, пустого, но на твоем месте я бы избегал даже этого.
 MasterMastic09 июн. 2013 г., 20:11
Хорошо, спасибо, что ответили. Я думаю, для этого есть документация.
 sth09 июн. 2013 г., 17:42
@ Ken: Дело в том, что написание спецификаций исключений имеет в основном негативные последствия. Единственный положительный эффект заключается в том, что он показывает программисту, какие исключения могут возникнуть, но поскольку компилятор не проверяет его разумным образом, он подвержен ошибкам и поэтому не стоит много.
 Jan Turoň17 февр. 2017 г., 20:27
Как говорит @StudentT: функция обязана гарантировать, что не будут выбрасываться другие исключения. Если они это сделают, программа завершается как следует. Объявить бросок означает Я не обязан справляться с этой ситуацией и у вызывающей стороны должно быть достаточно информации для этого. Не объявлять исключения означает, что они могут возникать где угодно и с ними можно обращаться где угодно. Это, конечно, анти-ООП беспорядок. Это отказ проекта отлавливать исключения в неправильных местах. Я бы порекомендовал не выбрасывать пустой, так как исключения являются исключительными, и большинство функций в любом случае должны выбрасывать пустой.
 MasterMastic09 июн. 2013 г., 12:05
Я не знаю, зачем мне выбрасывать исключение, и я не смог бы его упомянуть. Даже если он вызывается другой функцией, я знаю, какие исключения могут быть выданы. Единственная причина, которую я вижу, это то, что это утомительно.
 SmallChess23 сент. 2016 г., 04:03
Не верно. Должна быть написана спецификация исключения, но идея в том, чтобы сообщить, какие ошибки должен попытаться поймать вызывающи

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

С C ++ мое общее правило - использовать только спецификации броска, чтобы указать, что метод не может бросить. Это сильная гарантия. В противном случае предположим, что он может выбросить что угодно.

от вопрос, нужно потратить несколько минут на вопрос: каков вывод следующего кода?

#include <iostream>
void throw_exception() throw(const char *)
{
    throw 10;
}
void my_unexpected(){
    std::cout << "well - this was unexpected" << std::endl;
}
int main(int argc, char **argv){
    std::set_unexpected(my_unexpected);
    try{
        throw_exception();
    }catch(int x){
        std::cout << "catch int: " << x << std::endl;
    }catch(...){
        std::cout << "catch ..." << std::endl;
    }
}

Ответ: как уже отмечалосьВо, программа вызываетstd::terminate() и, следовательно, ни один из обработчиков исключений не будет вызван.

Детали: Первыйmy_unexpected()ункция @ вызывается, но поскольку она не перебрасывает соответствующий тип исключения дляthrow_exception() прототип функции, в конце концов,std::terminate() называется. Таким образом, полный вывод выглядит так:

user @ user: ~ / tmp $ g ++ -o исключением.test кроме.test.cpp
user @ user: ~ / tmp $ ./except.tes
хорошо - это было неожиданно
terminate вызывается после создания экземпляра i
Aborted (ядро сброшено)

- http: //blogs.msdn.com/b/larryosterman/archive/2006/03/22/558390.asp)

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

   class MyClass
   {
    size_t CalculateFoo()
    {
        :
        :
    };
    size_t MethodThatCannotThrow() throw()
    {
        return 100;
    };
    void ExampleMethod()
    {
        size_t foo, bar;
        try
        {
            foo = CalculateFoo();
            bar = foo * 100;
            MethodThatCannotThrow();
            printf("bar is %d", bar);
        }
        catch (...)
        {
        }
    }
};

Когда компилятор видит это с помощью атрибута throw (), компилятор может полностью оптимизировать переменную «bar», потому что он знает, что исключить исключение из MethodThatCannotThrow () невозможно. Без атрибута throw () компилятор должен создать переменную «bar», потому что, если MethodThatCannotThrow выдает исключение, обработчик исключения может / будет зависеть от значения переменной bar.

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

Ваш ответ на вопрос