C++ 诺雷顿的意义是什么?

C++ 诺雷顿的意义是什么?,c++,c++11,attributes,noreturn,C++,C++11,Attributes,Noreturn,提供以下示例: [[ noreturn ]] void f() { throw "error"; // OK } 但是我不明白[[noreturn]]的意义是什么,因为函数的返回类型已经是void 那么,noreturn属性的意义是什么?如何使用它?这意味着该功能将无法完成。在调用f()之后,控制流永远不会命中语句: void g(){ f(); //遥不可及: std::coutnoreturn不告诉编译器函数不返回任何值。它告诉编译器控制流不会返回给调用方。这允许编译器进行

提供以下示例:

[[ noreturn ]] void f() {
    throw "error";
    // OK
}
但是我不明白
[[noreturn]]
的意义是什么,因为函数的返回类型已经是
void


那么,
noreturn
属性的意义是什么?如何使用它?

这意味着该功能将无法完成。在调用
f()
之后,控制流永远不会命中语句:

void g(){
f();
//遥不可及:

std::cout
noreturn
不告诉编译器函数不返回任何值。它告诉编译器控制流不会返回给调用方。这允许编译器进行各种优化——它不需要保存和恢复调用周围的任何易失性状态,它可以消除死码uld否则将跟随调用等。

noreturn属性应该用于不返回调用方的函数。这并不意味着无效函数(返回调用方的函数-它们只是不返回值),而是指控制流在函数完成后不会返回调用函数的函数(例如,退出应用程序、永远循环或抛出异常的函数,如示例中所示)


编译器可以使用它进行一些优化并生成更好的警告。例如,如果
f
具有noreturn属性,编译器可以在您编写
f();g()时警告您
g()
是死代码类似地,编译器将知道在调用
f()

类型后不会警告您缺少返回语句。从理论上讲,
void
是在其他语言
unit
top
中调用的。它的逻辑等价物为True。任何值都可以合法地转换为
void
(每种类型都是
void
)的子类型。将其视为“宇宙”集合;世界上所有的值都没有共同的操作,因此对
void
类型的值没有有效的操作。换句话说,告诉你某个东西属于宇宙集合不会给你任何信息——你已经知道它了。因此,以下是合理的:

(void)5;
(void)foo(17); // whatever foo(17) 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;
}
但是下面的赋值是完全合法的,因为
throw
被编译器理解为不返回:

void f(int y) {
    int x = y!=0 ? 100/y : throw exception();
    cout << x << endl;
}

遗憾的是,C++不允许它,可能是因为实际的原因。相反,它给了你使用<代码> [[NORETURN] ] /COD>属性的能力,这有助于指导编译器优化和警告。

< P>以前的答案正确地解释了Nordurn是什么,但不是<强>为什么它存在。我不认为“优化”。注释的主要目的是:不返回的函数是罕见的,通常不需要被优化。相反,我认为Nordurn的主要Re'Tre是避免假阳性警告。例如,考虑这个代码:

int f(bool b){
    if (b) {
        return 7;
    } else {
        abort();
    }
 }

如果abort()未标记为“noreturn”,编译器可能会警告此代码有一个路径,其中f未按预期返回整数标记为不返回它知道代码是正确的。

gcc/clang@TemplateRex:Compile with
-Wno return
,您将收到一条警告。可能不是您期望的警告,但它可能足以告诉您编译器知道什么是
[[noreturn]
,并且可以利用它。(我有点惊讶,
-Wunreachable code
没有生效…)@TemplateRex:很抱歉
-Wmissing noreturn
,警告意味着流分析确定
std::cout
不可访问。我手头没有足够的新gcc来查看生成的程序集,但是如果调用
操作符(coliru中有一个(-s-o-标志)确实删除了“无法访问”代码。有趣的是,在没有
[[noreturn]]
提示的情况下删除无法访问的代码。@TemplateRex:所有代码都在同一个翻译单元中,并且可见,因此编译器可以推断
[[noreturn]]
来自代码。如果此翻译单元只有在其他地方定义的函数声明,编译器将无法删除该代码,因为它不知道函数不返回。这就是属性应该帮助编译器的地方。那么像这样的函数不应该返回,但可以返回呢?应该吗它具有noreturn属性?不,它不应该——如果控制流有可能返回到调用方,它就不能具有
noreturn
属性。
noreturn
只能在函数保证在控制流返回到调用方之前终止程序的情况下使用——例如:因为您调用exit()、abort()、assert(0)等。这是否包括通过异常抛出返回(可以这么说),或者抛出的异常是否跳过
noreturn
函数外部的
catch
或是否禁止从
noreturn
函数内部抛出异常?@slipd.Thompson如果对noreturn函数的调用包装在try块中,则上catch块中的任何代码都将再次被视为可访问。@slipd.Thompson否,它是可访问的无法返回。引发异常不会返回,因此如果每个路径都引发异常,则它是
noreturn
。处理该异常与它返回的异常不同。调用后
try
中的任何代码仍然无法访问,如果不是
void
,则不会发生任何对返回值的赋值或使用。N任何东西都可以被强制转换为
void
void
而不会计算为
true
false
或其他任何东西。所有东西都可以被强制转换为
void
void
永远不会计算为
true
,因为
bool
void
的子类型,而不是相反的。同样,所有东西都是空的
void f(int y) {
    int x = y!=0 ? 100/y : throw exception();
    cout << x << endl;
}
noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();
int f(bool b){
    if (b) {
        return 7;
    } else {
        abort();
    }
 }