在c++中使用C动态内存函数避免分段错误

Using C dynamic memory functions in C++ to avoid Segmentation Fault

本文关键字:函数 分段 错误 内存 动态 c++      更新时间:2023-10-16

我正试图安全地从我期望发生的分割故障中恢复。我试图避免检查使用我的canAlloc()函数在这里。当canAllow返回false时,A0(如果你没有看到它,它是Ackermann的)应该抛出一个异常,我可以在main方法中捕获它。checkTable和saveInTable都是使用map<int hash, int value>来存储A0的返回值的函数。

    bool canAlloc(){
     bool reBool = false;
     int * memch = (int*)calloc (10000, sizeof(int));
     reBool = (memch != NULL);
     free(memch);
     return reBool;
    }

    int A0(int m, int n){
if(!canAlloc()) throw;
int reInt = checkReturnTable(m,n);
if(reInt == -1){        
    if(m == 0){
        return n + 1;
    } else if(m > 0){
           if(n == 0){
                reInt = A0(m-1,1);
           } else if(n > 0){
                reInt = A0(m-1, A0(m,n-1));
           }
    }
    saveInReturnTable(m,n,reInt);
    return reInt;
} else return reInt;
}

来自注释:

在main中我有一个try-catch块来捕获任何异常try{} catch(...){}。据我所知,这三个句号应该捕捉抛出的任何异常。据我所知,throw关键字在没有任何说明符的情况下抛出异常,但仍然可以被三个点捕获。

段错误不是c++的例外。它指示程序失败,导致操作系统向进程发送SIGSEGV信号。您将无法直接catch SIGSEGV信号;你必须设置一个信号处理程序和…嗯,在这一点上,它变得棘手,因为不清楚您是否可以从信号处理程序中抛出异常。

没有指定异常的throw会重新抛出当前异常;它只在catch块中有意义。

当你的系统无法进一步扩展堆栈时,你可能会得到SIGSEGV,可能是因为你已经耗尽了虚拟内存。这意味着您的一个函数调用失败,因为没有空间放置其参数或局部变量或返回地址等。没有干净的方法可以恢复,这就是为什么系统产生分割故障。

如果这个错误是因为calloc()不能分配内存,你不会得到一个分段错误;你会得到一个零返回值。你可以在"内存不足"异常发生时干净且同步地引发它。但这不是你的问题。

您无法从分段错误中恢复,因为一旦发生错误,您的程序就不再处于良好定义的状态,并且也没有机制可以回滚到良好定义的状态。

分段错误总是以这样或那样的方式导致编程错误,您必须简单地避免它。在c++中,您可以简单地捕获来自动态分配的异常:
 T * p;
 try { p = new T; }
 catch(const std::bad_alloc & e) { /* ... */ }

通常不需要那么多手工操作,因为您可以将动态分配包装在合适的管理容器中(如unique_ptrshared_ptr),并且您应该在程序流中可以处理错误并继续有意义的地方捕获异常(甚至不仅仅是分配异常)。

(由于异常,通常不需要在调用端检查可能抛出函数的结果——这就是使用异常的全部意义。)


如果出于某种原因,您只想分配原始内存,而不构造任何对象,您可以通过以下两种方式实现:

// Method #1, the C++ way:
void * addr = ::operator new(n);  // will throw std::bad_alloc on error
// Method #2, the manual way:
void * addr = std::malloc(n);
if (!addr) throw std::bad_alloc();  // throw exception manually, handled elsewhere