[[noreturn]]函数如何具有返回类型?

时间:2013-08-21 07:43:53

标签: c++ function return noreturn

我遇到了“高度可读”和“优雅”代码的“漂亮”示例,但我理解它时遇到了麻烦:

struct S {

    [[noreturn]] virtual inline auto f(const unsigned long int *const)
                         –> void const noexcept;
};

这是我理解的(如果我错了请纠正我):

  • f()S
  • 的成员函数
  • virtual - 可以被派生类重写
  • inline - 编译器应尝试生成代码以调用f而不是正常调用
  • const - 该功能无法更改任何S成员
  • noexcept - 该函数永远不会抛出(不能抛掷或不允许投掷)
  • 参数:指向const
  • const unsigned long int指针
  • auto .... -> void - 后缀返回类型void
  • [[noreturn]] - 它永远不会return s

以下是我的主要关注点:

  • 如果某个函数声明为[[noreturn]],则从不会返回其调用者;那么如何才能有一个返回类型void?无论如何,这个函数的返回类型有什么意义?
  • 此代码是否会使用int代替void进行编译?
  • 这样的功能会有什么用处?抛出异常?
  • 此函数完成执行后(}之后)代码的流程在哪里?

我无法在VS2013预览版上运行此代码,所以我猜这些功能尚未实现。

我对此非常好奇,所以如果有人能解释我会很感激!干杯

4 个答案:

答案 0 :(得分:19)

[[noreturn]]是一个具有任何语义的属性。但是,它不会改变声明函数的方式:C ++中的所有普通函数(即除构造函数,析构函数和转换运算符之外的所有函数)都具有声明的返回类型。添加任何属性都不会更改此规则。

[[noreturn]]属性的目的可能是表明函数永远不会以正常方式返回。鉴于该函数也被声明为noexcept,它基本上意味着相应的函数也不能抛出异常。具有类似行为的函数的一个示例是exit(),其终止程序。我可以想象实现某种应用程序循环的函数也可以符合条件。在任何情况下,[[noreturn]]都告诉系统相应的函数永远不会正常返回,即掉落函数(“after}”)可能会导致未定义的行为。

答案 1 :(得分:6)

  

如果函数声明为[[noreturn]],它永远不会返回其调用者;那怎么会有一个返回类型无效?无论如何,这个函数的返回类型有什么意义?

this Q& A你可以看到noreturn是一种告诉编译器函数不返回的方法。通常这意味着它要么具有无限循环(通常在应该无限期运行的服务器中看到),要么调用exit()terminate()等,退出应用程序而不返回main。
[[noreturn]]是可选的,即您没有来指定它。它是一个属性,即定义/声明函数的基本语法保持不变,因此函数具有以具有与任何其他函数一样的返回类型。

  

这段代码是用int而不是void编译的吗?

是的,它会,虽然编译器可能会警告你从一个永不返回的函数返回的东西没有意义。

  

这样的功能会有什么用处?抛出异常?

首先想到的是一些无限循环,例如:处理服务器上的传入请求。对于[[noreturn]]函数也可以抛出异常,但这不是一个真正的选项,因为它明确地说noexcept。抛出将触发对std::terminate()的调用,导致程序终止本身但主要是实现定义的堆栈展开量,实际上意味着[[noreturn]]仍然适用。

  

在此函数完成执行后(在})之后代码的流程在哪里?

该函数永远不会达到其结束}。它要么无休止地运行(直到某人拔出插头),要么异常退出,即通过程序终止。换句话说,如果函数不再执行,它还没有真正完成但是中止执行,并且没有程序也没有控制流可以去。

答案 2 :(得分:2)

其他答案很棒,但我会为

提供替代答案
  

如果函数声明为[[noreturn]],它永远不会返回其调用者;那怎么会有一个返回类型无效?无论如何,这个函数的返回类型有什么意义?

您可能需要返回类型(以及非void返回类型)的一个原因是该函数是否覆盖了超类方法。

struct Parent {
   virtual int f()=0;
}

struct Child {
    [[noreturn]] override int f() noexcept { ... }
};

在某些情况下,编译器将能够使用[[noreturn]]来生成更好的代码。但在其他情况下,f可能被称为多态,因此需要符合其父级签名。

答案 3 :(得分:0)

<块引用>

如果一个函数被声明为[[noreturn]],它永远不会返回给它的调用者;那么它怎么会有一个返回类型void呢?无论如何,这个函数中的返回类型有什么意义?

我发现了一个非空函数 [[noreturn]] 的实际例子。在一种情况下,当在 ?: 运算符中使用时提供正确的 ?: 运算符结果类型:

template <class T> [[noreturn]] T fail(char const *s) noexcept { puts(s); exit(1); }
enum E { V1, V2 };
int f(E e) {
  return (e == V1) ? 1 : (e == V2) ? 2 : fail<E>("bad e");
}

注意:人们可能会觉得 [[noreturn]] 运算符中的 ?: 函数在计算 ?: 结果类型时可能会被忽略。但这是不可能的,因为 [[noreturn]] 不是表达式结果类型的一部分(fail<T>("") 具有结果类型 T 而不是 [[noreturn]] T)。

<块引用>

这样的函数有什么实际用途?抛出异常?

请参阅上面的此类函数 fail 的示例。