如何在c ++中捕获内存不足?

in *_*eps 38 c++ exception try-catch

任何人都可以告诉我如何捕获内存异常?

对于前

try
{
    while(true)
    {
        int i = new int;
    }
}
catch( ? <--- what should be put here?)
{
    //exception handling
}
Run Code Online (Sandbox Code Playgroud)

还有这个,

queue<int> q;
try
{
     while(true)
     {
          q.push(10);
     }
}
catch( ? <---- what should be put here?)
{
     //error handling
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*som 50

抓住std::bad_alloc.

您还需要一个处理错误的策略,因为您要做的许多事情都需要内存(即使它只是在关闭之前向用户显示错误).一种策略是在启动时分配一块内存,并在尝试使用更多内存之前delete在异常处理程序中分配一块内存,以便有一些可用.

  • 请注意,在实际情况中,在抛出和捕获错误之间,一些内存可能已经通过堆栈展开(例如局部“std::string”变量的破坏)被释放。通常,“std::bad_alloc”的处理程序将相当“位于程序的外部”,而内存可能会在深度嵌套的情况下耗尽。只是说,像打印错误消息这样的事情并不一定会失败。 (2认同)

bwD*_*aco 19

正如其他人所说,你想要抓住的是std::bad_alloc.您还可以使用catch(...)或catch(exception& ex)捕获任何异常; 后者允许在异常处理程序中读取和使用异常数据.

Mark Ransom已经指出,当程序无法分配更多内存时,即使打印错误消息也可能失败.考虑以下程序:

#include <iostream>

using namespace std;

int main() {
    unsigned long long i = 0;
    try {
        while(true) {
            // Leaks memory on each iteration as there is no matching delete
            int* a = new int;
            i++;
        }
    } catch(bad_alloc& ex) {
        cerr << sizeof(int) * i << " bytes: Out of memory!";
        cin.get();
        exit(1);
    }

    return 0; // Unreachable
}
Run Code Online (Sandbox Code Playgroud)

(我强烈建议将程序编译为32位,以避免在64位计算机上运行系统内存.32位程序无法分配超过4 GB的内存,或Windows上默认为2 GB.)

当第一个bad_alloc被抛入无限while循环时,控制被传递给catch块,但程序仍然失败并带有未处理的异常.为什么?在尝试打印时,另一个在异常处理程序中bad_alloc抛出.您可以使用调试器对此进行验证:在该行设置断点,在调试器中运行该程序,然后在到达断点后逐步执行每个语句.一个例外将在抛出的语句.cerrcatch(bad_alloc& ex)bad_alloccerr

因此,要正确处理内存不足的情况,您需要预留一些内存,以便在退出之前打印错误消息.否则,程序将在尝试打印错误消息时在未处理的异常上崩溃.为此,您可以分配在异常处理程序中释放的内存块,正如Mark Ransom建议的那样:

// Reserve 16K of memory that can be deleted just in case we run out of memory
char* _emergencyMemory = new char[16384];
// ...
try {
// ...
} catch(bad_alloc& ex) {
    // Delete the reserved memory so we can print an error message before exiting
    delete[] _emergencyMemory;

    cerr << sizeof(int) * i << " bytes: Out of memory!";
    cin.get();
    exit(1);
}
//...
Run Code Online (Sandbox Code Playgroud)

  • 更新了代码以通过引用捕获异常。但是,此代码“有意地”避免了RAII,因为它专门用于泄漏内存以进行演示。这就是答案的重点。 (2认同)

GWW*_*GWW 14

catch (std::bad_alloc& ba){
    cerr << "bad_alloc caught: " << ba.what() << endl;
}
Run Code Online (Sandbox Code Playgroud)

作为一个注释你应该阅读bdonlan的评论.呼吁cerr很可能会失败.Mark Ransom在他的回答中提出了一个缓解这个问题的好策略.

  • 注意:由于内存不足,打印到cerr可能会失败. (8认同)

Naw*_*waz 5

你应该catch是一个类型的对象std::bad_alloc.

或者,您也可以使用以下nothrow版本new:

int *pi = new (nothrow) int[N]; 
if(pi == NULL) 
{
   std::cout << "Could not allocate memory" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

使用它时,如果new失败则不会抛出异常.相反,它只是返回NULL你检查的内容,然后再继续.