BЈо*_*вић 178 c++ attributes c++11 noreturn
[dcl.attr.noreturn]提供以下示例:
[[ noreturn ]] void f() {
throw "error";
// OK
}
Run Code Online (Sandbox Code Playgroud)
但我不明白有什么意义[[noreturn]],因为函数的返回类型已经存在void.
那么,该noreturn属性的重点是什么?它应该如何使用?
sep*_*p2k 200
noreturn属性应该用于不返回调用者的函数.这并不意味着void函数(它们确实返回调用者 - 它们只是不返回值),而是在函数完成后控制流不会返回到调用函数的函数(例如退出应用程序的函数,永远循环或抛出例子中的异常).
编译器可以使用它来进行一些优化并生成更好的警告.例如,如果f具有noreturn属性,编译器可能会g()在您编写时警告您是否为死代码f(); g();.类似地,编译器将知道在调用之后不会警告您缺少return语句f().
Ste*_*non 60
noreturn不告诉编译器该函数不返回任何值.它告诉编译器控制流不会返回给调用者.这允许编译器进行各种优化 - 它不需要保存和恢复调用周围的任何易失性状态,它可以使用死代码来消除否则将跟随调用的任何代码等.
Dav*_*eas 26
这意味着该功能无法完成.调用后,控制流程永远不会出现在语句中f():
void g() {
f();
// unreachable:
std::cout << "No! That's impossible" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
编译器/优化器可以以不同方式使用该信息.编译器可以添加上述代码无法访问的警告,并且可以g()以不同方式修改实际代码,例如支持延续.
Nad*_*'El 14
以前的答案正确地解释了noreturn是什么,但不是为什么它存在.我不认为"优化"注释是主要目的:不返回的函数很少,通常不需要优化.相反,我认为noreturn的主要存在理由是避免误报警告.例如,考虑以下代码:
int f(bool b){
if (b) {
return 7;
} else {
abort();
}
}
Run Code Online (Sandbox Code Playgroud)
如果abort()没有被标记为"noreturn",编译器可能会警告这个代码有一个路径,其中f不会按预期返回一个整数.但是因为abort()被标记为没有返回它知道代码是正确的.
Ela*_*zar 11
键入从理论上讲,void就是所谓的在其他语言unit或top.它的逻辑等价是True.任何值都可以合法地转换为void(每种类型都是子类型void).把它想象成"宇宙"集; 世界上的所有值都没有共同的操作,因此对类型值没有有效的操作void.换句话说,告诉你属于宇宙集的东西不会给你任何信息 - 你已经知道了.所以以下是合理的:
(void)5;
(void)foo(17); // whatever foo(17) does
Run Code Online (Sandbox Code Playgroud)
但下面的任务不是:
void raise();
void f(int y) {
int x = y!=0 ? 100/y : raise(); // raise() returns void, so what should x be?
cout << x << endl;
}
Run Code Online (Sandbox Code Playgroud)
[[noreturn]],另一方面,有时也被称为empty,Nothing,Bottom或Bot和是的逻辑等效假.它根本没有值,并且这种类型的表达式可以转换为任何类型的(即子类型).这是空集.请注意,如果有人告诉你"表达式foo()的值属于空集",那么它具有很高的信息性 - 它告诉你这个表达式永远不会完成它的正常执行; 它会中止,抛弃或挂起.这恰恰相反void.
所以以下没有意义(伪C++,因为noreturn它不是一流的C++类型)
void foo();
(noreturn)5; // obviously a lie; the expression 5 does "return"
(noreturn)foo(); // foo() returns void, and therefore returns
Run Code Online (Sandbox Code Playgroud)
但是下面的赋值是完全合法的,因为throw编译器可以理解为不返回:
void f(int y) {
int x = y!=0 ? 100/y : throw exception();
cout << x << endl;
}
Run Code Online (Sandbox Code Playgroud)
在完美的世界中,您可以使用noreturn上述函数的返回值raise():
noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();
Run Code Online (Sandbox Code Playgroud)
可悲的是,C++不允许它,可能是出于实际原因.相反,它使您能够使用[[ noreturn ]]有助于指导编译器优化和警告的属性.