是什么构成了未指定的块范围静态或线程存储持续时间变量的失败初始化?

Xeo*_*Xeo 7 c++ static-initialization language-lawyer c++11

在回答了这个问题而没有在标准文件中找到令人满意的答案后,我开始疑惑.该标准规定了以下wrt初始化提到的变量:

§6.7 [stmt.dcl] p4

[...]否则这个变量在第一次控制通过其声明时被初始化; 这样的变量在初始化完成后被认为是初始化的.如果通过抛出异常退出初始化,则初始化未完成,因此下次控制进入声明时将再次尝试初始化.

没有提到可能导致初始化被重试的情况,如果除了抛出异常之外的其他任何事情都失败了(longjmp()thead退出,信号等等).

我是否忽略了标准中的任何内容?我一遍又一遍地查看初始化,声明和异常条款,甚至通过快速搜索"静态"来查询CWG缺陷表,但找不到任何相关内容.

这是标准中的一个不明确的(并且作为这样的缺陷)吗?

Nic*_*las 2

C++ 规范只能定义 C++ 规范中包含的内容。请记住:C++ 规范定义了它所定义的虚拟机的行为。如果它没有定义某些事情可能发生,那么它当然也没有定义 C++ 围绕它没有说可能发生的事情的行为。

\n\n

根据 C++ 规范,线程可以通过三种方式退出:从其主函数返回、通过其主函数抛出异常以及直接进程退出(与std::terminate或类似函数一样)。简而言之,C++ 线程不能以任何其他方式退出。标准C++中没有ExitThread函数。同样,std::thread无法在外部或内部杀死线程。

\n\n

因此,根据定义,任何导致 C++ 认为不可能发生的事情的事情都是未定义的。我想这甚至不会是“未定义的行为”;在 C++11 真正规定线程交互如何工作之前,线程就处于这个模糊的空间中。

\n\n

对于“信号”来说也是如此,无论它们是什么。C++ 规范并没有说这些会导致函数退出。这里有龙。

\n\n

至于longjmp,这是由 的行为所涵盖的longjmp。当您使用longjmp退出函数时,该函数永远不会完成,就像您使用throwand一样catch。在 C++ 中,对象仅在其构造函数完成后才被构造。因此,该对象的初始化从未完成,并且未初始化。

\n\n

我没有 ISO C 规范(C++ 引用了 的行为longjmp),但 C++11 强烈建议您可以将throw/catchlongjmp/等同setjmp,只要您获得未定义的行为:

\n\n
\xc2\xa718.10 [support.runtime] p4:\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

函数签名 longjmp(jmp_buf jbuf, int val) 在此国际标准中具有更多限制行为。如果用 catch 和 throw 替换 setjmp 和 longjmp 会调用任何自动对象的任何非平凡析构函数,则 setjmp/longjmp 调用对具有未定义的行为。

\n
\n\n

所以我不认为这是未明确说明的。它可能布置得不那么漂亮和整齐,但所有的部分都在那里。

\n