Using C dynamic memory functions in C++ to avoid Segmentation Fault
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.
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 a catch
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.
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:
T * p;
try { p = new T; }
catch(const std::bad_alloc & e) { /* ... */ }
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
or shared_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:
// 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
精彩评论