【问题标题】:How to check memory allocation failures with new operator?如何使用 new 运算符检查内存分配失败?
【发布时间】:2011-10-13 13:43:57
【问题描述】:

就在最近,我将项目的语言从 C 切换为使用 C++。 对于 C,我使用了 malloc,然后我检查 malloc 是否成功,但对于 C++,我使用“new”来分配内存,我想知道您通常如何检查内存分配失败。

从我的谷歌搜索中,我没有看到类似以下内容。

char *buf = new (nothrow)char[10];

我还看到了以下内容。

try{} catch(bad_alloc&) {}

但是下面的呢?我正在使用一些 chrome 库例程来使用智能指针。

例如,我的代码如下。

scoped_array<char> buf(new char[MAX_BUF]);

使用智能指针很棒,但我只是不确定如何检查内存分配是否成功。 我是否需要用 nothrow 或 try/catch 分成两个单独的语句? 您通常如何在 C++ 中进行这些检查?

我们将不胜感激。

【问题讨论】:

  • 你打算在失败时做什么。除了日志,您无能为力。正常的 new 会引发一个异常,该异常会启动堆栈的展开,直至您退出应用程序或进入事件循环。这两个地方都适合记录失败(因此允许您将日志记录在一个地方)。

标签: c++ memory-management smart-pointers


【解决方案1】:

好吧,你调用 new 会抛出 bad_alloc,所以你必须抓住它:

try
{
    scoped_array<char> buf(new char[MAX_BUF]);
    ...
}
catch(std::bad_alloc&) 
{
    ...
}

scoped_array<char> buf(new(nothrow) char[MAX_BUF]);
if(!buf)
{
   //allocation failed
}

我的回答是智能指针传播异常。所以如果你用普通的 throwing new 分配内存,你必须捕获一个异常。如果您使用 nothrow new 进行分配,则必须检查 nullptr。在任何情况下,智能指针都不会在此逻辑中添加任何内容

【讨论】:

  • 请注意,通常您不会将每个 new 包装在其自己的 try 块中。取而代之的是,您可以在程序中的任何位置捕获到您可以对其进行有用的操作。
【解决方案2】:

我不想这么说,但 IMO,你走错了方向(不幸的是,你得到的其他答案也没有真正为你指明正确的方向)。

与其在不同种类的智能指针和/或new 的普通变体和 nothrow 变体之间进行选择,不如可能从你正在做的事情中至少再退后两步,并且用集合替换您手动管理的动态数据结构。这可能不是总是是正确的选择,但至少根据我的经验,这是经常很多的正确方法。标准库有许多可能性(向量、双端队列、列表、集合等),您可以使用其中一种而不是直接与new 和公司打交道。

默认情况下,它们将使用一个分配器,该分配器最终使用new 的正常(抛出)变体。因此,您通常希望将大部分代码放在一个相当高级别的 try 块中,并有一个 catch 子句来处理那里的内存不足。

当/如果您确实需要直接处理分配内存的问题,很有可能您仍然希望在库中提供与标准容器类似的接口,以便它可以与普通算法和迭代器一起使用。当您达到这一点时,您使用现有容器的初步体验将得到很好的回报,即使这可能是一段路。

【讨论】:

  • +1 最佳答案:其他答案是向 C 程序员提供答案的字面尝试。但实际上他们需要重新考虑如何完成内存管理。
  • 非常感谢您的建议。让我尝试执行您的建议。
  • 我不同意:标准容器也会生成分配,所以仅仅相信容器实际上是不够的。换句话说,这个问题仍然有效,或者对标准容器更有效。顶级尝试是无法管理的,在更好的情况下为您提供日志(但您的应用程序仍将崩溃)。
  • @AdrianMaire:我说的是“相当高的水平”,不一定是“顶级”水平。关键是你应该让它传播到你知道如何处理它的水平——基本上容器本身所能做的就是失败。在更高的级别上,您可能(例如)缓存了可以释放的其他数据,以使此分配有机会成功(或者这可能只是尝试缓存某些内容,而只是允许失败)。或者失败可能意味着程序必须退出。但是容器本身甚至无法猜测哪个适用,所以它不应该捕获异常。
【解决方案3】:

在 C++ 中,new 有两种主要的内存分配方式,每种方式都需要不同的错误检查。

标准的new 操作符会在失败时抛出std::bad_alloc 异常,这可以像普通异常一样处理

try {
  char* c = new char[100];
} catch (std::bad_alloc&) {
  // Handle error
}

或者替代newnothrow 版本将在失败时简单地返回NULL

char* c = new (std::nothrow) char[100];
if (!c) {
  // Handle error
}

我很好奇分配失败时您希望做什么?如果没有可用于分配对象的内存,那么在此过程中通常可以做的事情很少。

【讨论】:

  • “在这个过程中通常可以做的事情很少。” - 频率取决于MAX_BUF 的值。
  • @Steve 哦,在分配错误后可以更正。我很少看到任何正确执行的代码。
  • 通常“优雅地失败”是可以期待的最好结果。
  • @JaredPar:从好的方面来说,提问者是一名 C 程序员,并且已经费心检查malloc 的结果。对我来说,这表明能够处理内存不足的机会高于平均水平 :-) 显然,这在很大程度上取决于代码的类型——对于某种服务(或 Web 服务器)等),bad_alloc 的理想结果可能是向客户端返回指示失败的响应,这可能需要 比失败的内存少得多。对于桌面应用程序,您至少需要尽力保存用户数据。以此类推。
  • @Steve 内存不足处理程序的问题虽然很少经过测试,但随着时间的推移,静默内存分配会插入到处理程序中。看到这种情况发生了很多次(并且在处理程序中明显有 OOM 后跟 OOM 的崩溃报告)。恕我直言,如果您没有明确运行强制 OOM 和您的处理程序的检查,那么您最好只是让进程崩溃而无需处理。
【解决方案4】:

您仍然需要检查内存分配失败。

要么

scoped_array<char> buf;

try {
  buf.reset( new char[MAX_BUF] );
} catch( std::bad_alloc& ) {
  // Handle the failure
}

或者

scoped_array<char> buf( new(std::nothrow)char[MAX_BUF] );

if( buf.get() == NULL ) {
   // Handle the failure
}

【讨论】:

    猜你喜欢
    • 2012-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    相关资源
    最近更新 更多