当前位置: 首页 > 知识库问答 >
问题:

如果make_shared/make_unique可以抛出bad_alloc,为什么它不是一个常见的做法有一个尝试捕捉块?

孟均
2023-03-14

make_shared的CppReference页面显示(与make_ unique相同)

可能会抛出std::bad_alloc或T的构造函数抛出的任何异常。如果抛出异常,函数将无效。

这意味着在发生故障时可以抛出std::bad_alloc exeception。“函数没有效果”隐含地意味着它不能返回null ptr。如果是这种情况,为什么将make_shared/make_ unique始终写入try-catch块不是常见的做法?

使用make_shared的正确方法是什么?在try-catch块内?或者检查nullptr?

共有2个答案

鲁滨海
2023-03-14

抛出bad_alloc有两个效果:

  • 它允许在调用方层次结构中的某个位置捕获和处理错误。
  • 它产生明确定义的行为,无论是否发生这种处理。

这种明确定义的行为的默认方式是,通过调用< code>std::terminate()以快速但有序的方式终止进程。请注意,在调用< code>terminate()之前,堆栈是否展开是由实现定义的(但是,对于给定的实现,仍然是定义良好的)。

这与未处理的failed malloc()有很大不同,例如,后者(a)在取消引用返回的空指针时导致未定义的行为,以及(b)让执行轻松地进行,直到(并超越)那一刻,通常会在此过程中累积更多的分配失败。

接下来的问题是,调用代码应该在哪里以及如何捕获和处理异常。

在大多数情况下,答案是它不应该。

处理程序要做什么?实际上有两种选择:

  • 以比默认未处理异常处理更有序的方式终止应用程序。
  • 在其他地方释放一些内存并重试分配。

这两种方法都增加了系统的复杂性(尤其是后者),这需要在特定的环境中证明是正确的——更重要的是,在其他可能的故障模式和缓解措施的背景下。(例如,已经包含非软件故障保护的关键系统最好快速终止,让这些机制发挥作用,而不是在软件中瞎折腾。)

在这两种情况下,在调用方层次结构的更高层次上进行任何实际处理都可能比在进行失败分配时更有意义。

如果这些方法都没有增加任何好处,那么最好的方法就是让默认的std::terminate()处理开始。

金子轩
2023-03-14

我认为有两个主要原因。

>

  • 动态内存分配失败通常被认为是一种不允许优雅处理的情况。程序终止了,就这样。这意味着我们通常不会检查所有可能的<code>std::bad_alloc</code>。还是将<code>std::vector::push_back

    并非每个可能的异常都必须在直接呼叫端捕获。有人建议投掷与接球的关系应比一大得多。这意味着您可以在更高级别捕获异常,将多个错误路径“收集”到一个处理程序中。T 构造函数引发的情况也可以这样处理。毕竟,例外是例外。如果堆上的对象构造非常可能引发,以至于您必须检查每个此类调用,则应考虑使用不同的错误处理方案(std::optionalstd::expected等)。

    无论如何,检查nullptr绝对不是确保std::make_unique成功的正确html" target="_blank">方法。它永远不会返回 nullptr - 要么成功,要么抛出。

  •  类似资料:
    • 当异常在构造函数中被抛出时,其中创建了多个对象,必须做些什么来清理内存。例如。 我的直觉是,将每个对new的调用放在一个单独的try-catch组中,并删除之前为其调用了,但这太冗长的所有对象(第一个try组不调用析构函数,第二个类调用第一个类的析构函数,第三个类调用前两个类的析构函数,以此类推)。我的问题是:最常见的处理方法是什么? 另外,假设类对象包含一个不是用new创建的对象(因为它在堆栈上

    • 我已经用Java编写代码一段时间了。但有时,我不知道什么时候应该抛出异常,什么时候应该捕获异常。我正在做一个有很多方法的项目。层次结构是这样的- 所以目前我正在做的是-我在所有方法中抛出异常并在方法A中捕获它,然后将其记录为错误。 但我不确定这是否是正确的方法?或者我应该开始在所有方法中捕获异常。这就是为什么这种混乱始于我的 - 我什么时候应该抓住异常与何时应该抛出异常。我知道这是一个愚蠢的问题,

    • 问题内容: 我在编写Traveling Salesman程序时遇到了这个问题。对于内部循环,我尝试了 但是在该列表中添加另一个点时会导致被抛出。 但是,当我将循环更改为 循环运行良好,没有引发异常。 这两个都是for循环,那么为什么一个抛出异常却另一个没有抛出异常呢? 问题答案: 正如其他人解释的那样,迭代器检测到对基础集合的修改,这是一件好事,因为它可能会导致意外的行为。 想象一下下面的无迭代器

    • 我试图将两个“Employee”对象添加到树集中: 但它引发了一个ClassCastException: 但是如果我只向TreeSet添加一个对象: 或者如果我使用哈希集: 那么它就是成功的。为什么会发生异常,如何修复它?

    • 问题内容: 我需要捕捉一些从PHP本机函数抛出的警告,然后处理它们。 特别: DNS查询失败时,它将引发警告。 / 不起作用,因为警告也不例外。 我现在有2个选择: 似乎有点过分,因为我必须使用它来过滤页面中的每个警告(这是真的吗?); 调整错误报告/显示,以使这些警告不会在屏幕上显示,然后检查返回值;如果为,则找不到主机名的记录。 这里的最佳做法是什么? 问题答案: 设置和还原错误处理程序 一种

    • 这是Google Guice调用代码: 这是个例外: 我的问题是消息没有告诉我缺少哪一个特定的方法。有没有好的方法来调试这个?这可能是一个Maven传递依赖问题吗?