有一种方法叫做 foo 这有时会返回以下错误:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Abort

有没有办法,我可以使用一个 try-catch 阻止停止此错误终止我的程序(我想要做的就是返回 -1)?

如果是这样,它的语法是什么?

我还能怎么处理 bad_alloc 在C++中?

有帮助吗?

解决方案

您可以像任何其他例外捕获它:

try {
  foo();
}
catch (const std::bad_alloc&) {
  return -1;
}
.

你可以从这一点开始做的事情取决于你,但它在技术上肯定是可行的。

其他提示

一般来说,你 不能, ,而 不应该尝试, ,以响应此错误。 bad_alloc 指示无法分配资源,因为没有足够的内存可用。在大多数情况下,你的程序不能指望应付这种情况,并且很快终止是唯一有意义的行为。

更糟糕的是,现代操作系统经常过度分配:在这样的系统, mallocnew 一个有效的指针是否可以,即使没有足够的可用内存 – std::bad_alloc 永远不会被抛出,或者至少不是内存耗尽的可靠标志。相反,试图 查阅资料 然后,分配的内存将导致分段错误,这是不可捕获的(您可以 手柄 的分段故障信号,但之后不能恢复程序)。

捕捉时你唯一能做的事 std::bad_alloc 是为了记录错误,并尝试通过释放未完成的资源来确保安全的程序终止(但是如果程序适当地使用RAII,则在错误抛出后的正常堆栈展开过程中会自动完成)。

在某些情况下,程序可能会尝试释放一些内存并重试,或者使用辅助内存(=磁盘)而不是RAM,但这些机会仅存在于具有严格条件的非常特定的场景中:

  1. 应用程序必须确保它在不会过度使用内存的系统上运行, ,即它在分配时而不是以后发出失败的信号。
  2. 应用程序必须能够释放内存 立即, ,在此期间没有任何进一步的意外分配。

非常罕见的是,应用程序可以控制点1-用户空间应用程序 从来没有 做,这是一个系统范围的设置,需要root权限才能更改。1

好吧,假设你已经确定了第1点。你现在可以做的是例如使用 LRU缓存 对于您的一些数据(可能是一些可以按需重新生成或重新加载的特别大的业务对象)。接下来,您需要将可能失败的实际逻辑放入支持重试的函数中—换句话说,如果它被中止,您可以重新启动它:

lru_cache<widget> widget_cache;

double perform_operation(int widget_id) {
    std::optional<widget> maybe_widget = widget_cache.find_by_id(widget_id);
    if (not maybe_widget) {
        maybe_widget = widget_cache.store(widget_id, load_widget_from_disk(widget_id));
    }
    return maybe_widget->frobnicate();
}

…

for (int num_attempts = 0; num_attempts < MAX_NUM_ATTEMPTS; ++num_attempts) {
    try {
        return perform_operation(widget_id);
    } catch (std::bad_alloc const&) {
        if (widget_cache.empty()) throw; // memory error elsewhere.
        widget_cache.remove_oldest();
    }
}

// Handle too many failed attempts here.

但即使在这里,使用 std::set_new_handler 而不是处理 std::bad_alloc 提供相同的好处,并且会简单得多。


1 如果你正在创建一个应用程序, 是否 控制点1,你正在阅读这个答案,请给我发一封电子邮件,我真的很好奇你的情况。

什么是C++标准所规定的行为 new c++?

通常的概念是,如果 new 操作者不能分配的动态存储器的要求的大小,那么它应该把一个异常的类型 std::bad_alloc.
然而,更多的东西会发生甚至之前 bad_alloc 异常:

C++03部分3.7.4.1.3: 说的

一个分配功能的未分配储存可以调用的目前安装new_handler(18.4.2.2),如果有的话。[注:一程序提供的分配功能可以得到的地址的当前安装new_handler使用set_new_handler功能(18.4.2.3).] 如果分配功能的声明具有一个空的例外规定(15.4),扔(),未分配储存,应当返回的一个空的指针。任何其它分配功能的未分配储存应只指明的失败抛-ing一个例外的类std::bad_alloc(18.4.2.1)或某一类源自std::bad_alloc.

考虑下列代码样本:

#include <iostream>
#include <cstdlib>

// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
    std::cerr << "Unable to satisfy request for memory\n";

    std::abort();
}

int main()
{
    //set the new_handler
    std::set_new_handler(outOfMemHandler);

    //Request huge memory size, that will cause ::operator new to fail
    int *pBigDataArray = new int[100000000L];

    return 0;
}

在上述例子中, operator new (最有可能)将无法分配空间,为100,000,000个整数和功能 outOfMemHandler() 将称,该程序将中止后 发出错误信息。

因为在这里看到默认的行为 new 操作时无法履行存储器的请求,是要叫 new-handler 功能反复,直至它能够找到足够的存储器或没有更多新的处理程序。在上述实例中,除非我们呼 std::abort(), outOfMemHandler() 将会是 所谓的重复.因此,处理程序应确保,未来分配成功,或登记另一种处理程序,或者登记册没有处理程序,或者不使返回(即终止程序)。如果没有新的处理程序和分配失败,操作者将把一个例外。

什么是的 new_handlerset_new_handler?

new_handler 是typedef为指针指向一个函数,以及返回什么都没有, set_new_handler 是一个函数,以及返回 new_handler.

是这样的:

typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();

set_new_handler的参数为指针的功能操作 new 应该呼吁,如果它不能拨出所要求的记忆。其返回值是指向以前登记的处理程序功能,或null如果没有以前的处理程序。

如何处理内存条件C++?

给定的行为 new一个设计良好的用户程序应该处理的内存条件,通过提供正确的 new_handler这不下列之一:

使更多的存储器可用: 这可以允许下一个存储器分配尝试的内部操作新的循环,要取得成功。一种方式来实现这个是分配一大块的存在程序启动时,然后释放,它使用的程序的第一时间的新的处理程序是援引。

安装不同的新的处理程序: 如果当前的新的处理程序不能做任何更多的存储器可用,还有另外一个新的处理程序,可以,那么当前的新的处理程序可以安装其他新的处理程序在它的地方(通过调用 set_new_handler).下一次操作者的新电话的新的处理程序功能,它将得到一个最近安装。

(对这一主题的变化是一个新的处理程序修改它自己行为,所以接下来的时间调用的,它并不同的东西。实现这一点的一个办法是有的新的处理程序修改静态的,名字空间的特定的或全球的数据,影响新的处理程序的行为。)

卸载的新的处理程序: 这样做是通过一个空的指针 set_new_handler.没有新的处理程序安装, operator new 将把一个异常((敞篷车) std::bad_alloc)时存分配是不成功的。

扔一个例外 敞篷车 std::bad_alloc.这种例外不被抓到 operator new, 但将传播给网站发起的请求,用于存储器。

不返回: 通过调用 abortexit.

我不会建议这一点,因为 bad_alloc 意味着你是 内存不足.最好是放弃而不是试图恢复。但是,这是您要求的解决方案:

try {
    foo();
} catch ( const std::bad_alloc& e ) {
    return -1;
}

我可能会为此建议一个更简单(甚至更快)的解决方案。 new 如果无法分配内存,operator将返回null。

int fv() {
    T* p = new (std::nothrow) T[1000000];
    if (!p) return -1;
    do_something(p);
    delete p;
    return 0;
}

我希望这可以帮助!

让你的 foo程序退出 方式:

#include <stdlib.h>     /* exit, EXIT_FAILURE */

try {
    foo();
} catch (const std::bad_alloc&) {
    exit(EXIT_FAILURE);
}
.

然后写一个调用实际程序。由于地址空间分离,因此shell程序的状态始终定义。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top