什么是不归路?

时间:2012-05-10 16:22:26

标签: c++ c++11 attributes noreturn

[dcl.attr.noreturn]提供了以下示例:

[[ noreturn ]] void f() {
    throw "error";
    // OK
}

但我不明白[[noreturn]]的重点是什么,因为函数的返回类型已经是void

那么,noreturn属性的重点是什么?它应该如何使用?

5 个答案:

答案 0 :(得分:185)

noreturn属性应该用于不返回调用者的函数。这并不意味着void函数(它们确实返回调用者 - 它们只是不返​​回值),而是在函数完成后控制流不会返回到调用函数的函数(例如退出应用程序的函数,永远循环或抛出异常,例如你的例子。)

编译器可以使用它来进行一些优化并生成更好的警告。例如,如果f具有noreturn属性,编译器可能会在您编写g()时警告您f(); g();为死代码。同样,在调用f()之后,编译器将不会警告您缺少返回语句。

答案 1 :(得分:57)

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

答案 2 :(得分:26)

这意味着该功能无法完成。调用f()后,控制流将永远不会出现声明:

void g() {
   f();
   // unreachable:
   std::cout << "No! That's impossible" << std::endl;
}

编译器/优化器可以以不同方式使用该信息。编译器可以添加上述代码无法访问的警告,并且可以以不同方式修改g()的实际代码,例如支持延续。

答案 3 :(得分:12)

以前的答案正确地解释了noreturn是什么,但不是为什么它存在。我不认为“优化”注释是主要目的:不返回的函数很少,通常不需要优化。相反,我认为noreturn的主要存在理由是避免误报警告。例如,请考虑以下代码:

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

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

答案 4 :(得分:10)

从理论上讲,void是其他语言unittop中的名称。它的逻辑等价物是 True 。任何值都可以合法地转换为void(每种类型都是void的子类型)。把它想象成&#34;宇宙&#34;组; 所有世界中的值没有共同的操作,因此对类型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]]有时被称为emptyNothingBottomBot,并且是 False的逻辑等价物。它根本没有值,并且这种类型的表达式可以转换为任何类型的(即子类型)。这是空集。请注意,如果有人告诉你&#34;表达式foo()的值属于空集&#34;它高度提供信息 - 它告诉你这个表达式永远不会完成它的正常执行;它会中止,抛弃或挂起。它与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 ]]属性,这有助于指导编译器优化和警告。