C++ 带有捕获std::bad_alloc的策略

C++ 带有捕获std::bad_alloc的策略,c++,coding-style,new-operator,try-catch,C++,Coding Style,New Operator,Try Catch,因此,我在开发过程中经常使用Qt,我非常喜欢它。Qt对象的常用设计模式是使用new分配它们 几乎所有的示例(尤其是Qt设计器生成的代码)都绝对没有检查std::bad_alloc异常。由于分配的对象(通常是小部件等)很小,因此这几乎不成问题。毕竟,如果您无法分配20个字节之类的内容,那么很可能您无法解决这个问题 目前,我采用了一种策略,将“大”(大小超过一两页的任何内容)分配包装在try/catch中。如果失败,我会向用户显示一条消息,几乎任何更小的消息,我只会让应用程序崩溃,出现std::ba

因此,我在开发过程中经常使用Qt,我非常喜欢它。Qt对象的常用设计模式是使用
new
分配它们

几乎所有的示例(尤其是Qt设计器生成的代码)都绝对没有检查
std::bad_alloc
异常。由于分配的对象(通常是小部件等)很小,因此这几乎不成问题。毕竟,如果您无法分配20个字节之类的内容,那么很可能您无法解决这个问题

目前,我采用了一种策略,将“大”(大小超过一两页的任何内容)分配包装在try/catch中。如果失败,我会向用户显示一条消息,几乎任何更小的消息,我只会让应用程序崩溃,出现
std::bad_alloc
异常

所以,我想知道在这方面的思想流派是什么

检查每个
新操作是否是一项好政策?还是只有我认为有可能失败的

此外,在处理资源可能受到更大限制的嵌入式环境时,情况显然完全不同。我是在桌面应用程序的上下文中提问的,但我也对涉及其他场景的答案感兴趣。

问题不在于“捕捉到哪里”,而是“捕捉到异常时该怎么办”

如果您想检查,最好使用catch,而不是使用
包装

    #include <new>
    x = new (std::nothrow) X();
    if (x == NULL) {
        // allocation failed
    }
#包括
x=新的(std::nothrow)x();
如果(x==NULL){
//分配失败
}
我的惯例是

  • 在非交互式程序中,在主级别捕获并在那里显示适当的错误消息

  • 在一个有用户交互循环的程序中,捕获也在循环中,这样用户可以关闭一些东西并尝试继续


例外的是,在其他一些地方,捕获是有意义的,但很少。我通常在用户启动操作时捕获异常。对于控制台应用程序,这意味着在
main
中,对于GUI应用程序,我将处理程序放在单击按钮处理程序等位置


<>我相信在一个动作的中间捕获异常是没有意义的,用户通常期望操作成功或完全失败。如果分配失败,并且您的应用程序在没有该内存位的情况下无法继续,为什么还要检查错误呢

当可以处理错误时,当有一种有意义的恢复方法时,处理错误。如果对错误无能为力,就让它传播。

main()
中处理它(或在Qt中使用等效的顶级异常处理程序)

原因是std::bad_alloc要么在耗尽内存空间时发生(32位系统上为2或3 GB,64位系统上不发生),要么在耗尽交换空间时发生。现代堆分配器没有被调整为从交换空间运行,因此这将是一个缓慢、嘈杂的死亡过程——很可能你的用户会提前杀死你的应用程序,因为它的UI不再响应。而在Linux上,操作系统的内存处理在默认情况下是如此糟糕,以至于你的应用程序可能会被自动终止


所以,你几乎无能为力。承认你有一个bug,看看你是否可以保存用户可能做过的任何工作。要做到这一点,最好尽可能地中止。是的,这实际上可能会丢失一些最后的用户输入。但正是这一行动很可能引发了这种局面。。我们的目标是保存您可以信任的任何数据。

这是一个相对较旧的线程,但在2012年执行new/delete覆盖时,当我搜索“std::bad_alloc”注意事项时,它确实出现了

我不会把“哦,好吧,你无论如何也做不了什么”作为一个可行的选择。 我个人在自己的分配中使用上面提到的“if(alloc()){}else{error/handling}”方式。通过这种方式,我可以恰当地处理和(或)在各自有意义的上下文中报告每个案例

现在,其他一些可能的解决方案包括: 1) 覆盖应用程序的新建/删除,您可以在其中添加自己的内存不足处理

尽管和其他海报一样,特别是在不了解特定上下文的情况下,主要的选择可能是关闭应用程序。 如果是这种情况,您希望处理程序预先分配所需的内存,或者使用静态内存,以便处理程序自身不会耗尽

在这里,您可能至少会弹出一个对话框,并说出以下内容: “应用程序内存不足。这是一个致命错误,现在必须自行终止。 应用程序必须在最低系统内存要求下运行。将调试报告发送到xxxx”。 处理程序还可以保存任何正在进行的工作等,以适应应用程序

无论如何,你都不想用它来做一些关键的事情,比如(警告,前面的业余幽默):航天飞机,心率监视器,肾透析机等等。 当然,这些东西需要更健壮的解决方案,使用故障保护、紧急垃圾收集方法、100%测试/调试/模糊等

2) 与第一个类似,使用自己的处理程序设置全局“set_new_handler()”,以捕获全局范围内的内存不足情况。
至少能像#1中提到的那样处理事情。

真正的问题是,如果你发现了std::bad#alloc异常,那你该怎么办?
大多数情况下,如果内存用完,你无论如何都会失败,可能会考虑结束你的程序。

确实不投新是一个可行的选择,但是如果在给定的代码块中有一些分配,它将比使用TIG/catch块更冗长。我百分之百同意“做什么”才是真正的问题,因为内存不足的情况确实限制了你能做多少事情来解决问题。与其说是“做什么”,不如说是“你能做什么?”