在 C++ 中使用 C 动态内存函数以避免分段错误
我正在尝试从预期发生的分段错误中安全地恢复。我试图避免使用我的 canAlloc() 函数进行检查。当 canAllow 返回 false 时,A0(如果您没有看到的话,这是 Ackermann 的)应该抛出一个异常,我可以在 main 方法中捕获该异常。 checkTable 和 saveInTable 都是使用 map
来存储 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
关键字在没有任何说明符的情况下抛出异常,但仍然可以通过三个点捕获。
I'm trying to safely recover from a segmentation fault I expect to happen. I'm trying to avoid it checking using my canAlloc() function here. When canAllow returns false, A0 (which is Ackermann's if you didn't see it) should throw an exception that I can catch in the main method. checkTable and saveInTable are both functions that use a map<int hash, int value>
to store returns from 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;
}
From a comment:
In main I have a try-catch block to catch any exception
try{} catch(...){}
. As I understand it the three periods should catch any exception thrown. And as I understand, thethrow
keyword throws the exception without any specifiers, but can still be caught by the three dots.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
分段错误不是 C++ 异常。它表示程序故障导致操作系统向您的进程发送 SIGSEGV 信号。您将无法直接
捕获
SIGSEGV 信号;你必须设置一个信号处理程序......好吧,此时它会变得棘手,因为不清楚你是否可以从信号处理程序中抛出异常。未指定异常的
throw
会重新抛出当前异常;它仅在catch
块内才有意义。当您的系统无法进一步扩展堆栈时,您可能会收到 SIGSEGV,这可能是因为虚拟内存已用完。这意味着您的一个函数调用失败,因为没有空间放置其参数或局部变量或返回地址等。没有干净的方法可以从中恢复,这就是系统生成分段错误的原因。
如果错误是因为 calloc() 无法分配内存,则不会出现分段错误;你会得到零返回值。当它发生时,您可以干净、同步地引发“内存不足”异常。但这不是你的问题。
A segmentation fault is not a C++ exception. It is indicative of a program failure that causes the OS to send a SIGSEGV signal to your process. You won't be able to
catch
a SIGSEGV signal directly; you'd have to set up a signal handler and ... well, it gets tricky at that point, because it is not clear that you can throw an exception from within a signal handler.A
throw
with no exception specified rethrows the current exception; it only makes sense inside acatch
block.You probably get the SIGSEGV when your system is unable to extend the stack any further, probably because you've run out of virtual memory. That means one of your function calls failed because there was no space to put its arguments or local variables or return address, etc. There is no clean way to recover from that, which is why the system generates the segmentation fault.
If the fault was because
calloc()
could not allocate memory, you'd not get a segmentation fault; you'd get a zero return value. And you could raise an 'out of memory' exception cleanly and synchronously when it happens. But that isn't your problem.您无法从分段错误中恢复,因为一旦发生错误,您的程序就不再处于明确定义的状态,并且也没有机制可以回滚到明确定义的状态。
分段错误始终是一种编程错误,您必须避免它。在 C++ 中,您可以简单地捕获来自动态分配的异常:
不过,通常不需要那么手动,因为您可以将动态分配包装在合适的管理容器中(例如
unique_ptr
或shared_ptr
),并且您应该在程序流程中能够处理错误并继续有意义的位置处捕获异常(甚至不仅仅是分配异常)。(由于异常,您通常不需要在调用方检查可能抛出函数的结果 - 这就是使用异常的全部意义。)
如果出于某种原因您只想分配原始内存,而不构造任何对象,您可以可以通过两种方式做到这一点:
You cannot recover from a segmentation fault, because once the fault occurs, your program is no longer in a well-defined state, and there's no mechanism to roll back to a well-defined state, either.
A segmentation fault is always a programming error in one way or another, and you must simply avoid it. In C++, you can simply catch exceptions coming from a dynamic allocation:
Usually there's no need to be quite that manual, though, since you would wrap your dynamic allocations inside suitable managing containers (like
unique_ptr
orshared_ptr
), and you should catch exceptions (not even just allocation ones) at points in your program flow where you are in a position to handle the error and continue meaningfully.(Thanks to exceptions you should not usually need to check the result of possibly throwing functions right at the call side - that's the whole point of using exceptions.)
If for some reason you just want to allocate raw memory, without constructing any object, you can do it in two ways: