Это безвозмездно сделал новый код, используя по существу тот же инструмент, выражающий то же обещание, несовместимое со старым кодом
Исправление: если функция нарушает спецификацию динамического исключения, std::unexpected
Вызванный, который вызывает неожиданный обработчик, который по умолчанию вызывает std::terminate
. Но обработчик может быть заменен пользовательской функцией. Если функция нарушает noexcept
, std::terminate
вызывается напрямую.
Обещания разные. throw()
означало «может делать неожиданные вещи, если пытается создать исключение». noexcept
означает «немедленно прекратит работу, если попытается создать исключение».
Это было только в C ++ 17, когда throw()
было сделано в точности эквивалентным noexcept
. Это произошло после 6 лет исключений спецификаций (включая throw()
).
Следует отметить, что разница unexpected
была явно процитирована в первых статьях о noexcept
,В частности:
Обратите внимание, что полезность noexcept(true)
в качестве подсказки по оптимизации выходит далеко за рамки узкого случая, представленного N2855. Фактически, это выходит за рамки построения перемещения: когда компилятор может с уверенностью обнаруживать не-генерирующие операции, он может оптимизировать большое количество кода и / или данных, предназначенных для обработки исключений. Некоторые компиляторы уже делают это для throw()
спецификаций, но, поскольку они несут накладные расходы неявного блока try / catch для обработки непредвиденных исключений, преимущества ограничены.
Неявный блок try / catchнеобходимо, потому что unexpected
должен вызываться после разматывания стека к функции throw()
. По сути, каждая функция throw()
выглядит следующим образом:
void func(params) throw()
try
{
<stuff>
}
catch(...)
{
std::unexpected();
}
Поэтому, когда исключение пытается покинуть функцию throw()
, исключение получает перехвачено и стек разворачивается. Более того, каждая функция throw()
должна иметь встроенный механизм исключения. Таким образом, независимо от стоимости блока try/catch
будет взиматься каждая throw()
функция.
В первой версии noexcept
исключение было прямым UB, а более поздние версии переключались на std::terminate
. Но даже с этим, нет гарантии, что раскрутить. Таким образом, реализации могут реализовать noexcept
более эффективным способом. Когда система ищет в стеке ближайшее предложение catch
, если оно достигает дна функции noexcept
, она может идти прямо к завершению без какого-либо механизма захвата.
Чтовызвал такую ненависть к throw ()?
Исправление: не повторное назначение конструкции не влечет за собой злого умысла. Особенно, когда изобретение новой конструкции позволит избежать нарушения совместимости, как показано выше.
Следует отметить, что throw()
считается эквивалентным функции noexcept
в терминах выражения noexcept
. То есть вызов функции throw()
не вызывает исключений, а выражение noexcept(empty_throw())
приведет к true
.
Следует также отметить, что в любом случае потребуется новое ключевое слово. Почему? Потому что throw(<stuff>)
в C ++ 98/03 уже имеет значение. noexcept(<stuff>)
имеет совсем другое значение для <stuff>
. Попытка поместить материал noexcept
внутрь спецификатора throw
будет ... трудной, с точки зрения синтаксического анализа.
Кроме того, теперь вы можете использовать это новое ключевое слово в качестве обобщенного выражения: noexcept(<expression>)
разрешается до true
, если ни один из вызовов внутри него не выдаст исключения. Это позволяет вам делать условную логику в зависимости от того, будут ли вещи вызывать исключения. Вам понадобится новое ключевое слово, чтобы сделать что-то подобное (или вам придется создать уродливый синтаксис, а в C ++ слишком много этого происходит).