Разница между спецификатором throw () C ++ 03 C ++ 11 noexcept

Есть ли какая-нибудь разница между throw() и noexcept, кроме проверки во время выполнения и во время компиляции, соответственно?

В этой статье Википедии о C ++ 11 говорится, что C ++ 03 выбрасывает спецификаторы устарели.
Почему так, достаточно ли noexcept, чтобы покрыть все это во время компиляции?

[Примечание: я проверил этот вопрос и эта статья, но не удалось определить вескую причину прекращения поддержки.]


person iammilind    schedule 11.10.2012    source источник
comment
Согласно этой хорошей статье также noexcept могут потребоваться проверки во время выполнения. Основное различие между ними в том, что взлом noexcept вызывает std::terminate, а взлом throw вызывает std::unexpected. Также в этих случаях немного другое поведение при раскручивании стека.   -  person Fiktik    schedule 11.10.2012
comment
Во время компиляции ничего не проверяется с некоторыми спецификациями исключений, которые проверяются во время выполнения для других. Это просто миф, созданный противниками спецификаций исключений C ++.   -  person curiousguy    schedule 01.11.2019


Ответы (3)


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

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

Таким образом, вы можете сделать что-то вроде этого:

struct<typename T>
{
  void CreateOtherClass() { T t{}; }
};

CreateOtherClass выдает исключения? Может, если конструктор по умолчанию T может. Как мы узнаем? Нравится:

struct<typename T>
{
  void CreateOtherClass() noexcept(is_nothrow_default_constructible<T>::value) { T t{}; }
};

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

Вы не можете этого сделать с throw().

person Nicol Bolas    schedule 11.10.2012
comment
+1 Полезный ответ, по крайней мере для меня. Все еще ищу ответ, в котором говорится, почему я хочу использовать noexcept. Я никогда не использовал спецификатор throw() и пытаюсь определить, действительно ли noexcept дает какие-либо преимущества (кроме проверенной компилятором документации). - person hmjd; 20.02.2013
comment
Только что нашел этот stackoverflow.com/questions/10787766 / ... - person hmjd; 20.02.2013
comment
@hmjd: Все еще ищу ответ, в котором говорится, почему я хотел бы использовать noexcept. Вы не найдете здесь ответа на этот вопрос, потому что это не тот вопрос, который был задан . - person Nicol Bolas; 21.02.2013
comment
Ага, я это знаю. Просто изучал noexcept и читал несколько вопросов / ответов по этому поводу. Самая важная причина, по которой я обнаружил, заключалась в том, что некоторые (возможно, все) контейнеры STL не будут использовать конструктор перемещения, если он не объявлен как noexcept, чего я не осознавал. - person hmjd; 21.02.2013
comment
Интересно, что случилось с тем, что деструкторы не должны вызывать функции, которые генерируют исключения. - person Alexander Oh; 26.08.2013
comment
@Alex: деструкторы могут вызывать функции метания. Они просто не могут позволить этим исключениям избежать вызова деструктора. - person Nicol Bolas; 26.08.2013
comment
@NicolBolas согласен. но если noexcept будет гарантией, компилятор может проверить, может ли функция вызывать деструктор. Таким образом можно предупредить программиста о том, что функция не является исключением или нет. - person Alexander Oh; 26.08.2013
comment
@Alex: noexcept - это гарантия. Если исключение пытается покинуть любую функцию, равную noexcept, будет вызвана std::terminate. - person Nicol Bolas; 26.08.2013
comment
@NicolBolas среда выполнения вызывает std::terminate. что ХУЖЕ! код может проникнуть в выпуски, в которых функции отмечены noexcept, и во время выполнения (то есть на сайтах клиентов) обнаруживаются нарушения. Я имел в виду, что компилятор гарантирует создание кода, который вообще не генерирует исключения. - person Alexander Oh; 26.08.2013
comment
@Alex: C ++ не является безопасным языком. Программист всегда несет ответственность за обеспечение целостности программы на C ++. То же самое и здесь: вам разрешено вызывать функции, не отмеченные noexcept. Язык полагается, что вы либо вызовете эти функции таким образом, чтобы они не вызывали выбросы, либо что вы вызовете эти функции таким образом, что вы поймаете любые исключения, которые они генерируют. Нет причин заставлять программистов на C ++ ограничиваться только функциями, явно помеченными noexcept. Это сломало бы тонны кода. - person Nicol Bolas; 26.08.2013
comment
позвольте нам продолжить это обсуждение в чате - person Alexander Oh; 26.08.2013
comment
@NicolBolas: Стоит отметить еще одно отличие. Если функция помечена throws(), то при возникновении исключения стек необходимо развернуть до области действия этой функции (чтобы все автоматические переменные в функции были уничтожены), в этот момент вызывается terminate() (через unexpected() ). Если функция помечена noexcept, то при возникновении исключения вызывается terminate (разворачивание стека определяется реализацией). - person Martin York; 17.09.2013
comment
@MartinYork Разница в семантике, не имеющая отношения к вызывающему коду. - person curiousguy; 27.10.2019
comment
@hmjd Самой важной причиной, которую я обнаружил, было то, что некоторые (возможно, все) контейнеры STL не будут использовать конструктор перемещения, если он не объявлен как noexcept Да, и изменение оформления функции с throw() на noexcept было в этом нет необходимости. - person curiousguy; 27.10.2019
comment
Спецификаторы исключений устарели, потому что спецификаторы исключений, как правило, ужасная идея. Тогда новый стиль столь же ужасен, как и те же самые критики, за исключением менее полезного исключения, некоторые исключения были удалены (который никогда не был частью центральный аргумент против старой спецификации) - person curiousguy; 27.10.2019
comment
@curiousguy: Знаете, после первого было несколько предложений. В самом деле, уже в следующем предложении речь идет именно об этом. Как будто я куда-то собирался с этим. Отсюда и использование квалификаторов, например, General и т. Д. - person Nicol Bolas; 27.10.2019
comment
@NicolBolas Они оказались бесполезными, но их плохая репутация похожа на плохую репутацию MI на многих языках, она основана на совершенно неуместных или поддельных заявлениях, плохом примере, плохом понимании ... Плохое понимание исправляется лучшим объяснения, не меняющие синтаксиса и семантики языка. Я не говорю, что всю мощь старой спецификации throw стоило сохранить, учитывая (относительно чрезвычайно небольшой) дополнительный язык и сложность, которую они вызывали, но очернение инструмента плохо и ужасно, когда оно распространяется. глубокое непонимание программирования. - person curiousguy; 27.10.2019

noexcept не проверяется во время компиляции.

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

Когда объявленная функция noexcept или throw() пытается вызвать исключение, единственное различие состоит в том, что одна вызывает terminate, а остальные вызывает unexpected, а последний стиль обработки исключений фактически устарел.

person CB Bailey    schedule 11.10.2012
comment
Но если виртуальная функция имеет _1 _ / _ 2_, проверка времени компиляции гарантирует, что переопределитель также имеет. - person curiousguy; 28.10.2019

std::unexpected() вызывается средой выполнения C ++, когда нарушается спецификация динамического исключения: исключение выбрасывается из функции, спецификация исключения которой запрещает исключения этого типа.

std::unexpected() также можно вызывать прямо из программы.

В любом случае std::unexpected вызывает установленный в данный момент std::unexpected_handler. По умолчанию std::unexpected_handler вызывает std::terminate.

person ma13    schedule 10.07.2017