终止应用程序并调用局部对象的析构函数

Terminate application AND call the destructors of local objects

本文关键字:对象 析构函数 调用局 应用程序 终止      更新时间:2023-10-16

我在main函数的堆栈上有一些对象:

int main(...)
{
   CFoo foo;
   CBar bar;
}

另外,我有一个函数,跟踪我的应用程序中的错误:

void Err(std::string msg)
{
   SomehowLogErrorMessage(msg);
   exit(1);
}
当我必须报告致命错误时,

Err函数绝对有用。我只是记录错误并终止应用程序-在发生此类错误后它无法恢复。但是,以"exit()"结束不会调用foo和bar析构函数——这是我实际期望的行为(但错误)。"abort()"也没有帮助。此外,我不能使用异常在main()中捕获它们。是否有其他方法来实现Err函数,以便它终止应用程序并正确清除堆栈对象?或者我是否应该重新设计我的错误处理?

谢谢!


注。顺便说一下,我不能发送WM_QUIT消息到我的主窗口吗?我不擅长WinAPI,但我的应用程序是纯Win32和我的Err()函数可以得到一个句柄到我的主窗口。它会起作用吗?

不是没有异常,或者从Err一直正常返回到调用堆栈。你需要展开堆栈

在c++中基本上有两种传播错误的方法:异常(你似乎随意地排除了它)和返回代码。

因为你不能使用异常,你将需要开始传递可能失败的函数的返回代码,并测试它们,看看是否需要停止并返回到main。如果不像这样展开堆栈,就无法保证析构函数被正确调用。

还要考虑一下,如果你的程序处于致命状态,析构函数实际上能够预期地清理吗?如果对象状态有缺陷,不能正确地删除该怎么办?而不是调用exit,你可以调用abort,这至少会留下一个核心,来帮助诊断问题,如果你进入一个不好的状态。对于不可用异常的致命错误,这是合理的选择。

仍然有C的setjmplongjmp。它会把你带回到main,所以程序会在离开main的作用域后像往常一样终止,在这种情况下,c++的析构器机制会销毁main中的局部对象。

当然,在c++中使用longjmp是不允许的,这是有充分理由的。它将跳过堆栈上的任何其他函数,因此它实际上只适用于main中的几个堆栈对象。

在堆上分配对象并在Err中手动delete它们可能更容易。

我会重新设计你的错误处理。最直接的做法是将控制权返回给main,让它执行正常的清理工作。异常通过堆栈展开提供此功能,但不能使用异常。好的,很好。有时候你就是不能使用异常。

所以不是让Err尝试关闭程序,而是让Err记录错误并返回错误代码。理想情况下,Err不应该做两项工作,无论如何,你试图让它做:1)记录错误,2)优雅地终止应用程序。

如果您的应用程序碰巧是多线程的,您可能有一个失败的容易退出。在错误日志线程中,通知一个"死亡"事件。让主线程等待这个事件以及它等待的任何其他事件(或通过QueueUserAPC或类似的方式向它注入一个作业)。当事件发出信号时,关闭应用程序。

我相信Exit会立即终止申请。要查看您期望的foobar的行为,必须超出范围。这意味着main函数必须以返回值正常结束。而不是调用Exit()从你的Err函数,你需要找到一种方法来返回到你的主函数,让它正常返回一个错误值。