“main”函数可以使用“noexcept”说明符声明吗?

28

以下的C++代码是否有效?

int main() noexcept
{
}

使用 clang++ 3.8.0g++ 7.2.0 编译这份代码没有问题(使用编译参数 -std=c++14 -O0 -Wall -Wextra -Werror -pedantic-errors

main 函数的 noexcept 声明中是否允许使用复杂条件(例如包含 noexcept 操作符)?

C++17 呢?据我所知,在此标准修订版中,noexcept 声明成为函数类型的一部分。


8
那真的很重要吗?如果异常逃离了“main”函数,就必须调用“std::terminate”。如果异常退出了一个“noexcept”函数,“std::terminate”也必须被调用。从所有有用的目的来看,“main” 已经是“noexcept”的。而且因为你既不能调用“main”也不能获取指向它的指针……那又有什么关系呢? - Nicol Bolas
@NicolBolas 有趣的笔记。我以为我能找到一个例子,其中抛出 int main()int main() noexcept 会产生不同的结果,但我无法快速做到。可能你是对的,根本就没有这样的例子。 - Constructor
@Constructor:有一个区别。如果您尝试通过noexcept函数抛出异常,则永远不会发生堆栈展开。而如果您尝试通过main抛出异常,则可能会发生堆栈展开;这取决于具体的实现。 - Nicol Bolas
@Constructor 这听起来更像是一个 bug,而不是其他什么。 - Passer By
2
@NicolBolas [except.terminate]/2。 - T.C.
显示剩余4条评论
2个回答

22

标准文档 [[basic.start.main]] 对 main 函数规定了以下约束条件:

实现应该允许:

— 返回 int 的无参数函数和

— 返回 int 的带有 (int, char 指针的指针) 参数的函数

此外:

定义 main 为已删除或声明 main 为内联、静态或 constexpr 的程序是非法的。

实践中,没有关于 mainnoexcept 限定符的规范。而另一方面,noexcept 可以作为任何函数的限定符。这意味着 main noexcept 不是非法的。


没有 noexcept 的 main 有什么区别?

由于标准对于 main 函数的 noexcept 限定符不是很明确,我们可以尝试推断一些行为并检查实现。

这里可得:

每当抛出异常并且搜索处理程序时遇到非抛出函数的最外层块时,就会调用 std::terminate 函数。

而对于异常的一般规则,可以从这里得知:

如果抛出异常并且未捕获,包括逃逸线程的初始函数、main 函数以及任何静态或线程本地对象的构造函数或析构函数,那么将调用 std::terminate。关于未捕获异常是否进行堆栈展开是由实现定义的。

这意味着在 main 函数中,无论 main 是否带有 noexcept 限定符,都始终会生成 std::terminate 调用。

实现方面:

确实,以下代码:

int main(int argc, char* argvp[]) {
  throw 1;
  return 0;
}

int main(int argc, char* argvp[]) noexcept {
  throw 1;
  return 0;
}

将会产生相同的汇编输出。例如在GCC中:

main:
        movl    $4, %edi
        subq    $8, %rsp
        call    __cxa_allocate_exception
        xorl    %edx, %edx
        movl    $1, (%rax)
        movl    typeinfo for int, %esi
        movq    %rax, %rdi
        call    __cxa_throw

这意味着无论有没有声明noexcept,在“main level”时,由于堆栈帧为空,它都将被解析为对std::terminate的调用。


int main() noexcept 和简单的 int main() 有什么区别? - Constructor
@Constructor 我尝试过对最终答案进行派生的差异。 - BiagioF

8
在C++14中,int main() noexcept;中的main类型是“返回int()函数”,在C++17中是“返回intnoexcept ()函数”。前者明确要求由[basic.start.main]支持,而后者则没有。这似乎是C++17中的缺陷。

4
如果有人比我更热心于报告核心问题,可以联系EDG的CWG主席Mike Miller,以便在两年后核心问题清单上出现该问题(假设此前未曾报告)。 - T.C.
问题将在两年后出现在核心问题清单上。太乐观了... :D - Language Lawyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接