9

我遇到了这个“高度可读”和“优雅”代码的“美丽”示例,但我在理解它时遇到了麻烦:

struct S {

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

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

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

以下是我的主要担忧:

  • 如果一个函数被声明为[[noreturn]],它永远不会返回给它的调用者;那么它怎么会有返回类型void呢?无论如何,这个函数中的返回类型有什么意义?
  • int这段代码会用而不是void例如编译吗?
  • 这样的功能有什么实际用途?抛出异常?
  • 该函数执行完毕后(after ),代码流向何方}

我无法让这段代码在 VS2013 Preview 上运行,所以我猜这些功能还没有实现。

我对此非常好奇,所以如果有人能解释一下,我将不胜感激!干杯

4

4 回答 4

19

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

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

于 2013-08-21T07:50:35.890 回答
6

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

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

例如,这段代码会用 int 而不是 void 编译吗?

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

这样的功能有什么实际用途?抛出异常?

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

此函数执行完毕后(在 } 之后),代码流向何方?

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

于 2013-08-21T08:50:29.027 回答
2

其他答案很好,但我将提供一个替代答案

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

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

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

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

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

于 2016-02-01T07:46:11.837 回答
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

于 2021-08-06T15:07:25.327 回答