【问题标题】:Policy with catching std::bad_alloc捕获 std::bad_alloc 的策略
【发布时间】:2010-11-21 10:31:13
【问题描述】:

所以我在开发过程中经常使用 Qt 并且喜欢它。 Qt 对象的通常设计模式是使用new 分配它们。

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

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

那么,我想知道这方面的学派是什么?

检查每个new 操作是否是好的策略?还是只有我认为有可能失败的那些?

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

【问题讨论】:

    标签: c++ coding-style new-operator try-catch


    【解决方案1】:

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

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

        #include <new>
        x = new (std::nothrow) X();
        if (x == NULL) {
            // allocation failed
        }
    

    我平时的做法是

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

    • 在具有用户交互循环的程序中,也要在循环中捕获,以便用户可以关闭某些内容并尝试继续。

    特殊情况下,在其他地方,catch 是有意义的,但很少见。

    【讨论】:

    • 确实 nothrow new 是一个可行的选择,但是如果在给定的代码块中有一些分配,它会比只使用 try/catch 块更冗长。我 100% 同意“做什么”是真正的问题,因为内存不足的情况确实限制了你可以做多少来解决问题。
    • 与其说是“做什么”,不如说是“你能做什么”
    • 如果你捕捉到它足够高,一些内存可能在堆栈展开期间被释放。您可以使用 new_handler 或 int flag = false; try { vector&lt;int&gt; v(1000); flag = true; doEventLoop(); } catch(bad_alloc) { if (flag) cout &lt;&lt; "I have 4k to use to prompt the user\n"; } 之类的技巧来确保释放某些内容
    • “提示用户”可能意味着弹出内存不足对话框和/或保存提示。当然在 linux 上你不会看到 bad_alloc,你只会得到一个页面错误。在任何操作系统上,您可能会发现它在应用程序发现内存不足之前就停止了,和/或在您的进程中拥有内存并不能帮助您显示对话框、保存文件等,因为 UI 和内核可以t 分配内存。但它可能值得一试,以防万一它工作(可能是因为你失败的分配是一个大对象,所以仍然有空闲内存)。
    • 是的,我指的是过度使用。我不知道您的 linux 进程会因为内存不足而崩溃的任何其他具体原因。不过,正如我所说,在任何操作系统上,内存不足都会导致 something 出错,即使只是其他应用程序也是如此。所以你可以尽力而为,但你不能指望这实际上会让用户恢复这种情况。
    【解决方案2】:

    真正的问题是应该你捕捉到 std::bad_alloc 异常吗? 在大多数情况下,如果你的内存用完了,你无论如何都注定要结束你的程序。

    【讨论】:

      【解决方案3】:

      这是一个相对较旧的线程,但是当我在 2012 年在这里进行新/删除覆盖时搜索“std::bad_alloc”注意事项时确实出现了。

      我不会将“哦,无论如何您都无能为力”的概念作为可行的选择。 我个人在我自己的分配中使用上面提到的“if(alloc()){} else { error/handling }”方式。通过这种方式,我可以正确处理和报告每个案例,或者在各自有意义的上下文中进行报告。

      现在,其他一些可能的解决方案是: 1) 覆盖应用程序的 new/delete,您可以在其中添加自己的内存不足处理。

      尽管与其他发帖者一样,特别是在不了解特定上下文的情况下,主要选项可能只是关闭应用程序。 如果是这种情况,您将希望您的处理程序预先分配它所需的内存,或者使用静态内存,因此希望它自己的处理程序不会耗尽。

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

      无论如何,您都不希望将它用于重要的事情,例如(警告、业余幽默):航天飞机、心率监测器、肾透析机等。 当然,这些事情需要更强大的解决方案,使用故障保险、紧急垃圾收集方法、100% 测试/调试/模糊测试等。

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

      【讨论】:

        【解决方案4】:

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

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

        因此,您无能为力。承认你有一个错误,看看你是否可以保存用户可能已经完成的任何工作。为了能够做到这一点,最好尽可能中止。是的,这实际上可能会丢失一些最后的用户输入。但正是这一行为可能引发了 OOM 情况。目标是保存您可以信任的任何数据。

        【讨论】:

          【解决方案5】:

          在您可以时处理异常。如果分配失败,并且您的应用程序在没有那部分内存的情况下无法继续运行,为什么还要检查错误?

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

          【讨论】:

          • 我愿意接受你和 AProgrammer 的,他们似乎都是很好的答案。由于AProgrammer是第一位的,我接受了他的。
          • 是的,是的。他的也更详细
          【解决方案6】:

          我通常在用户启动操作时捕获异常。对于控制台应用程序,这意味着在 main 中,对于 GUI 应用程序,我将处理程序放在按钮单击处理程序等位置。

          我认为在操作中间捕获异常没有什么意义,用户通常期望操作成功或完全失败。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-23
            • 1970-01-01
            • 1970-01-01
            • 2019-09-25
            相关资源
            最近更新 更多