[dcl.attr.noreturn] предоставляет следующий пример:
[[ noreturn ]] void f() {
throw "error";
// OK
}
но я не понимаю в чем смысл [[noreturn]]
, потому что возвращаемый тип функции уже есть void
.
Итак, в чем смысл этого noreturn
атрибута? Как это должно быть использовано?
c++
c++11
attributes
noreturn
BЈовић
источник
источник
Ответы:
Предполагается, что атрибут noreturn используется для функций, которые не возвращаются вызывающей стороне. Это не означает, что void функции (которые возвращают вызывающей стороне - они просто не возвращают значение), но функции, в которых поток управления не вернется к вызывающей функции после завершения функции (например, функции, которые выходят из приложения, цикл навсегда или выбросить исключения, как в вашем примере).
Это может быть использовано компиляторами для оптимизации и генерирования более качественных предупреждений. Например, если
f
есть атрибут noreturn, компилятор может предупредить вас о том,g()
что вы не работаете, когда пишетеf(); g();
. Точно так же компилятор будет знать, чтобы не предупреждать вас о пропущенных операторах возврата после вызововf()
.источник
execve
которая не должна возвращаться, но могла бы ? Должен ли он иметь атрибут noreturn ?noreturn
атрибут.noreturn
может использоваться, только если ваша функция гарантированно сделает что-то, что завершит программу, прежде чем поток управления сможет вернуться к вызывающей стороне - например, потому что вы вызываете exit (), abort (), assert (0) и т. д.noreturn
. Обработка этого исключения не совпадает с возвратом. Любой код вtry
после после вызова все еще недоступен, и если нет,void
то никакого присвоения или использования возвращаемого значения не произойдет.noreturn
не сообщает компилятору, что функция не возвращает никакого значения. Он сообщает компилятору, что поток управления не вернется к вызывающей стороне . Это позволяет компилятору выполнять различные оптимизации - ему не нужно сохранять и восстанавливать любое изменчивое состояние вокруг вызова, он может мертвым кодом исключать любой код, который в противном случае следовал бы за вызовом, и т. Д.источник
Это означает, что функция не будет завершена. Поток управления никогда не попадет в оператор после вызова
f()
:Информация может использоваться компилятором / оптимизатором различными способами. Компилятор может добавить предупреждение о том, что приведенный выше код недоступен, и он может модифицировать фактический код
g()
различными способами, например, для поддержки продолжений.источник
-Wno-return
и вы получите предупреждение. Вероятно, не тот, который вы ожидали, но достаточно сказать, что компилятор знает, что[[noreturn]]
есть, и он может воспользоваться этим. (Я немного удивлен, что-Wunreachable-code
не-Wmissing-noreturn
, предупреждение подразумевает, что анализ потока определил, чтоstd::cout
он недоступен. У меня недостаточно нового gcc, чтобы посмотреть на сгенерированную сборку, но я не удивлюсь, если вызов tooperator<<
будет отброшен-O1
что уже достаточно, чтобы сбросить этот недоступный код без[[noreturn]]
подсказки.[[noreturn]]
из кода. Если бы у этого модуля преобразования было только объявление функции, которая была определена где-то еще, компилятор не смог бы удалить этот код, поскольку он не знает, что функция не возвращает. Вот где атрибут должен помочь компилятору.Предыдущие ответы правильно объяснили, что такое noreturn, но не почему он существует. Я не думаю, что «оптимизационные» комментарии являются основной целью: функции, которые не возвращаются, редки и обычно не нуждаются в оптимизации. Скорее, я думаю, что основной смысл норетуры - избегать ложноположительных предупреждений. Например, рассмотрим этот код:
Если бы abort () не был помечен как «noreturn», компилятор мог бы предупредить, что у этого кода есть путь, где f не возвращает целое число, как ожидалось. Но поскольку abort () помечен как «нет возврата», он знает, что код верен.
источник
Тип теоретически говоря,
void
это то , что называется на других языкахunit
илиtop
. Его логический эквивалент - Истина . Любое значение может быть законно приведено кvoid
(каждый тип является подтипомvoid
). Думайте об этом как "вселенная"; нет никаких общих операций для всех значений в мире, поэтому нет допустимых операций для значения типаvoid
. Другими словами, говоря вам, что что-то принадлежит множеству вселенных, вы не получите никакой информации - вы уже это знаете. Итак, следующее звучит правильно:Но задание ниже не является:
[[noreturn]]
, С другой стороны, иногда называютempty
,Nothing
,Bottom
илиBot
и является логическим эквивалентом False . У него вообще нет значений, и выражение этого типа может быть приведено (то есть является подтипом) любого типа. Это пустой набор. Обратите внимание, что если кто-то скажет вам, что «значение выражения foo () принадлежит пустому набору», это очень информативно - это говорит о том, что это выражение никогда не завершит свое нормальное выполнение; это прервет, бросит или повесит. Это полная противоположностьvoid
.Таким образом, следующее не имеет смысла (псевдо-C ++, так как
noreturn
это не первоклассный тип C ++)Но приведенное ниже присваивание совершенно законно, поскольку
throw
компилятор понимает, что оно не возвращает:В идеальном мире вы могли бы использовать
noreturn
в качестве возвращаемого значения для функцииraise()
выше:К сожалению, C ++ не позволяет этого, вероятно, по практическим соображениям. Вместо этого он дает вам возможность использовать
[[ noreturn ]]
атрибут, который помогает направлять оптимизацию компилятора и предупреждения.источник
void
иvoid
никогда не имеет значениеtrue
илиfalse
или что - нибудь еще.true
, я имею в виду не «значениеtrue
типаbool
», а логический смысл, см. Соответствие Карри-Ховарда(void)true;
совершенно правильно, как и предполагает ответ.void(true)
это что-то совершенно другое, синтаксически. Это попытка создать новый объект типаvoid
, вызвав конструктор сtrue
аргументом; это терпит неудачу, среди других причин, потому чтоvoid
это не первый класс.