В чем смысл noreturn?
[dcl.АТР.noreturn] приводится следующий пример:
[[ noreturn ]] void f() {
throw "error";
// OK
}
но я не понимаю, в чем смысл [[noreturn]]
, потому что возвращаемый тип функции-это уже void
.
Итак, в чем же смысл ? Как он должен использоваться?
5 ответов:
атрибут noreturn должен использоваться для функций, которые не возвращаются вызывающему объекту. Это не означает, что функции void (которые возвращаются вызывающему-они просто не возвращают значение), но функции, где поток управления не вернется к вызывающей функции после завершения функции (например, функции, которые выходят из приложения, цикл навсегда или выбрасывают исключения, как в вашем примере).
это может быть использовано компиляторами, чтобы сделать некоторые оптимизации и генерировать лучше предупреждение. Например, если
f
с атрибутом noreturn, компилятор может предупредить вас оg()
будучи мертвым кодом, когда вы пишетеf(); g();
. Точно так же компилятор будет знать, чтобы не предупреждать вас о пропущенных операторах возврата после вызововf()
.
noreturn
не сказать компилятору, что функция не возвращает никакого значения. Он сообщает компилятору, что поток управления не вернется к вызывающему. Это позволяет компилятору делать различные оптимизации - ему не нужно сохранять и восстанавливать любое изменчивое состояние вокруг вызова, он может удалять мертвый код, который в противном случае следовал бы за вызовом, и т. д.
Это означает, что функция не будет выполнена. Поток управления никогда не попадет в Инструкцию после вызова
f()
:void g() { f(); // unreachable: std::cout << "No! That's impossible" << std::endl; }
информация может быть использована компилятором / оптимизатором по-разному. Компилятор может добавить предупреждение о том, что приведенный выше код недоступен, и он может изменить фактический код
g()
по-разному, например, для поддержки продолжения.
тип теоретически говоря,
void
это то, что называется в других языкахunit
илиtop
. Его логический эквивалент правда. Любое значение может быть законно приведено кvoid
(каждый тип является подтипомvoid
). Подумайте об этом как о наборе "Вселенная"; нет никаких операций, общих для все значения в мире, поэтому нет допустимых операций над значением типаvoid
. Иначе говоря, говоря вам, что что-то принадлежит к набору Вселенной дает вам никакой информации - вы уже знаете это. Итак, звучит следующее:(void)5; (void)foo(); // whatever foo() does
но задание не ниже:
void raise(); void f(int y) { int x = y!=0 ? 100/y : raise(); // raise() returns void, so what should x be? cout << x << endl; }
[[noreturn]]
, С другой стороны, иногда называютempty
,Nothing
,Bottom
илиBot
и является логическим эквивалентом ложные. Он вообще не имеет значений, и выражение этого типа может быть приведено к (т. е. является подтипом) любого типа. Это пустой набор. Обратите внимание, что если кто-то говорит вам "ценность выражение foo () принадлежит пустому набору" it is очень информативный - он говорит вам, что это выражение никогда не завершит свое нормальное выполнение; он будет прерван, бросить или повесить. Это полная противоположностьvoid
.поэтому следующее не имеет смысла (псевдо-C++, так как
noreturn
не является первоклассным типом C++)void foo(); (noreturn)5; // obviously a lie; the expression 5 does "return" (noreturn)foo(); // foo() returns void, and therefore returns
но задание ниже совершенно законно, так как
throw
понимается компилятором не так возвращение:void f(int y) { int x = y!=0 ? 100/y : throw exception(); cout << x << endl; }
в идеальном мире, вы могли бы использовать
noreturn
как возвращаемое значение для функцииraise()
выше:noreturn raise() { throw exception(); } ... int x = y!=0 ? 100/y : raise();
к сожалению, C++ не позволяет этого, вероятно, по практическим причинам. Вместо этого он дает вам возможность использовать
[[ noreturn ]]
атрибут, который помогает направлять оптимизацию компилятора и предупреждения.
предыдущие ответы правильно объяснили, что такое noreturn, но не почему он существует. Я не думаю, что комментарии "оптимизация" - это основная цель: функции, которые не возвращаются, редки и обычно не нуждаются в оптимизации. Скорее, я думаю, что главный смысл существования noreturn заключается в том, чтобы избегать ложноположительных предупреждений. Например, рассмотрим следующий код:
int f(bool b){ if (b) { return 7; } else { abort(); } }
если бы abort() не был отмечен "noreturn", компилятор мог бы предупредить об этом коде, имеющем путь где F не возвращает целое число, как ожидалось. Но поскольку abort () помечен как No return, он знает, что код правильный.