В чем смысл 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, он знает, что код правильный.