考虑以下可怕性:
#include <iostream>
struct thing
{
thing()
{
std::cout << "thing ctor\n";
throw 5;
}
};
void SomeTerminateHandler()
{
std::cout << "Uncaught exception!?\n";
}
int IHopeThisGetsCalledFirst()
{
std::cout << "IHopeThisGetsCalledFirst()\n";
std::set_terminate(SomeTerminateHandler);
return 2;
}
const int x = IHopeThisGetsCalledFirst();
const thing y;
int main()
{
}
输出:
IHopeThisGetsCalledFirst()
thing ctor
Uncaught exception!?
这依赖于静态初始化顺序(which I can mess with, for MSVS anyway),因此即使以下问题具有可接受的答案,它也不理想。
SomeTerminateHandler
中“捕获”异常,以便显示错误对话框或注明错误的详细信息?abort
在上述程序中SomeTerminateHandler
之后调用。为什么? This说“默认情况下,终止处理程序调用cstdlib的中止函数。” - 但我没有使用默认的终止处理程序,我的不会调用abort
。我可以做些什么来处理静态初始化时的异常。如果没有,为什么不呢?为什么语言中没有允许这样的内容?
答案 0 :(得分:2)
我可以在
SomeTerminateHandler
中“捕获”异常,以便显示错误对话框或注明错误的详细信息?
没有 - 只有异常处理程序才能访问抛出的异常。
在上述程序中abort
之后调用
SomeTerminateHandler
。为什么呢?
您的终止处理程序不得返回;标准(C ++ 11,18.8.3.1)要求它“终止程序的执行而不返回调用者” - 你链接到的页面也说同样的事情。如果你打破了这个要求,那么任何事情都可能发生。
我有什么办法可以处理静态初始化时的异常吗?
您可以在构造函数中捕获异常;或者你可以避免复杂的静态物体。
如果没有,为什么不呢?为什么语言中没有允许这样的内容?
我无法回答原因,但C ++并不能很好地处理复杂的静态对象。即使您的编译器确实有非标准扩展来指定初始化顺序,我建议尽可能避免使用它们。
答案 1 :(得分:1)
我可以做些什么来处理静态异常 初始化时间。如果没有,为什么不呢?为什么没有东西在里面 语言允许这个?
对于在文件范围外部链接或创建的用户定义对象,C ++没有任何明确定义的构造。对于未定义的初始化顺序等问题,通常会出现问题。如果没有明确定义初始化顺序等内容应该发生什么,那么定义有意义的try / catch行为就会很困难(如果有人将try / catch块放在哪里,例如,如果在任何编译单元中构造任何对象,系统可以扔?)。
对于一个更哲学的答案,我冒昧地猜测C ++旨在解决的一个问题是需要大量的全局对象。该语言并不打算为它们提供明确定义的行为,因为它们通常应该首先被避免。
如果你想快速修复,我们可以以懒惰的方式构建东西:
thing& my_thing()
{
static thing obj;
return obj;
}
这确保在第一次调用此函数之前不会构造thing
,这意味着它不会在主入口点之外构造,除非你有另一个全局对象调用它(直接或间接)通过它的构造函数。
最终如果你以这种方式一起避免用户定义类型的全局实例会更好,但如果你无法抗拒诱惑,我建议至少应用一种懒惰的初始化形式。
答案 2 :(得分:0)
我可以做些什么来处理静态初始化时的异常。如果没有,为什么不呢?
不,因为标准没有指定初始化顺序。
唯一不做的事情,或者至少最小化在main之前初始化的对象数量。将它们放在一个地方也是非常好的。
在上述程序中的SomeTerminateHandler之后调用abort。为什么?这说“终止处理程序默认调用cstdlib的中止函数。” - 但我没有使用默认的终止处理程序,我的也没有调用abort。
您的处理程序很可能未按时初始化(在初始化处理程序之前抛出异常)。