我可以捕获在 main() 之前抛出的异常吗?
Can I catch an exception thrown before main()?
我有一些库(实际上是用不同编译器编译的 tbb 库),在 main()
正确启动之前抛出异常。有办法捕捉到吗?
int main() { std::cout << "Hello World" << std::endl; }
给予
terminating with unexpected foreign exception
Abort (core dumped)
如果我 link 反对所述库(在此示例中未使用,但在其他代码中会使用)。
我发现这很有趣 source。它的构造基于 std::terminate
功能
他建议使用一种全局try...catch
(你不能再继续运行,但你可以根据例外情况采取行动):
[[noreturn]] void onTerminate() noexcept
{
if( auto exc = std::current_exception() ) {
// we have an exception
try{
rethrow_exception( exc ); // throw to recognize the type
}
catch( MyException const& exc ) {
// additional action
}
catch( MyOtherException const& exc ) {
// additional action
}
catch( std::exception const& exc ) {
// additional action
}
catch( ... ) {
// additional action
}
}
std::_Exit( EXIT_FAILURE );
}
并在发生异常时尽早注册此调用方:
const auto installed{ std::set_terminate(&handler) };
int main() {
// run...
}
但是你要知道,你不能确定std::set_terminate
会在任何实例化之前被调用。
一般来说,在标准 C++ 中无法捕获在构建全局变量(在任何函数范围之外)期间抛出的异常。
我认为最接近的可能性是使用 function-try-block 作为静态构造函数的主体。
class MyStatics
{
public:
MyStatics();
private:
X x; // construction may fail
Y y; // construction may fail
// etc
};
static MyStatics all_my_statics;
MyStatics::Mystatics() : x(), y() // implement using a function try block
try
{
if (some_condition) throw some_exception(); // construction may even fail here
}
catch (SomeException &)
{
// handler for SomeException
}
如果在 all_my_statics
的构造过程中抛出异常,那么它的任何 fully-constructed 成员都将被销毁(即 MyStatics
成员不存在于这样的 catch
块)。
在报告捕获到的异常后,catch
块中没有太多选项。主要选项将是;
- 抛出(或重新抛出)异常(因为
MyStatics
的构造失败)。该异常将导致 std::terminate()
被调用。
- 以其他被视为 "cleaner" 的方式终止程序。
吞下在静态构造期间抛出的异常不是一个好主意,因为程序(例如在 main()
内)将没有迹象表明它所依赖的静态没有被正确构造。
将静态对象放在函数中更常见
X &the_x()
try
{
static X thing;
return thing;
}
catch (Whatever &)
{
// handler
}
请记住,the_x()
的每次调用都将尝试构造 thing
直到其中一个成功(即,如果第一次抛出异常,第二次调用将尝试构造 thing
,等等)。但是,如果可以识别程序中 the_x()
的第一次调用并捕获异常(即将其包装在 try
/catch
中),则没有必要捕获后续的异常调用 - 因为,如果第一次调用没有抛出,thing
的构造已经成功,并且不会再次构造。
我有一些库(实际上是用不同编译器编译的 tbb 库),在 main()
正确启动之前抛出异常。有办法捕捉到吗?
int main() { std::cout << "Hello World" << std::endl; }
给予
terminating with unexpected foreign exception
Abort (core dumped)
如果我 link 反对所述库(在此示例中未使用,但在其他代码中会使用)。
我发现这很有趣 source。它的构造基于 std::terminate
功能
他建议使用一种全局try...catch
(你不能再继续运行,但你可以根据例外情况采取行动):
[[noreturn]] void onTerminate() noexcept
{
if( auto exc = std::current_exception() ) {
// we have an exception
try{
rethrow_exception( exc ); // throw to recognize the type
}
catch( MyException const& exc ) {
// additional action
}
catch( MyOtherException const& exc ) {
// additional action
}
catch( std::exception const& exc ) {
// additional action
}
catch( ... ) {
// additional action
}
}
std::_Exit( EXIT_FAILURE );
}
并在发生异常时尽早注册此调用方:
const auto installed{ std::set_terminate(&handler) };
int main() {
// run...
}
但是你要知道,你不能确定std::set_terminate
会在任何实例化之前被调用。
一般来说,在标准 C++ 中无法捕获在构建全局变量(在任何函数范围之外)期间抛出的异常。
我认为最接近的可能性是使用 function-try-block 作为静态构造函数的主体。
class MyStatics
{
public:
MyStatics();
private:
X x; // construction may fail
Y y; // construction may fail
// etc
};
static MyStatics all_my_statics;
MyStatics::Mystatics() : x(), y() // implement using a function try block
try
{
if (some_condition) throw some_exception(); // construction may even fail here
}
catch (SomeException &)
{
// handler for SomeException
}
如果在 all_my_statics
的构造过程中抛出异常,那么它的任何 fully-constructed 成员都将被销毁(即 MyStatics
成员不存在于这样的 catch
块)。
在报告捕获到的异常后,catch
块中没有太多选项。主要选项将是;
- 抛出(或重新抛出)异常(因为
MyStatics
的构造失败)。该异常将导致std::terminate()
被调用。 - 以其他被视为 "cleaner" 的方式终止程序。
吞下在静态构造期间抛出的异常不是一个好主意,因为程序(例如在 main()
内)将没有迹象表明它所依赖的静态没有被正确构造。
将静态对象放在函数中更常见
X &the_x()
try
{
static X thing;
return thing;
}
catch (Whatever &)
{
// handler
}
请记住,the_x()
的每次调用都将尝试构造 thing
直到其中一个成功(即,如果第一次抛出异常,第二次调用将尝试构造 thing
,等等)。但是,如果可以识别程序中 the_x()
的第一次调用并捕获异常(即将其包装在 try
/catch
中),则没有必要捕获后续的异常调用 - 因为,如果第一次调用没有抛出,thing
的构造已经成功,并且不会再次构造。