I'm new to C exception handling. I tried to throw an exception pointer and caught it but it seems the later caught exception isn't the same as which I thrown. Here's my code:
try {
bad_exception e2 = bad_exception();
cout << e2.what() << endl;
cout << &e2 << endl;
throw &e2;
}
catch (bad_exception* ex) {
cout << ex << endl;
cout << ex->what() << endl;
cout << (*ex).what() << endl;
}
output:
bad exception
00CFFCF8
00CFFCF8
Unknown exception
Unknown exception
I'd expected the later will show the same name "bad exception". Can you explain this?
updated:
It seems the exception has the "auto delete" feature? I tried throwing a pointer to normal object (not inherited from exception). But I can still access the object and its properties in the catch block.
try {
char str[5] = "eed8";
A a = A();
a.name1 = str;
cout << a.show() << endl;
cout << &a << endl;
throw &a;
}
catch (A* exp) {
cout << exp << endl;
cout << exp->show() << endl;
cout << exp->name1 << endl;
}
output:
eed8
007BF9DC
007BF9DC
eed8
eed8
CodePudding user response:
You should throw exceptions by value (usually).
The problem here is you are throwing a pointer to an object. Unfortunately, by the time the pointer is caught, the object that it is pointing to has been destroyed, and thus you have an invalid pointer.
try {
bad_exception e2 = bad_exception();
cout << e2.what() << endl;
cout << &e2 << endl;
throw &e2;
} // At this point the object "e2" goes out of scope
// Thus its destructor is called.
// So the pointer you threw now points at an invlalid object
// Thus accessign the object via this pointer is UB.
catch (bad_exception* ex) {
cout << ex << endl;
cout << ex->what() << endl;
cout << (*ex).what() << endl;
}
Rewrite it like this:
try {
bad_exception e2 = bad_exception();
cout << e2.what() << endl;
cout << &e2 << endl;
throw e2; // Throw a copy.
// Throw an object that gets copied to a secure location
// so that when you catch it is still valid.
}
catch (bad_exception const& ex) { // catch and get a reference to the copy.
cout << &ex << endl;
cout << ex.what() << endl;
}
If you absolutely must throw a pointer, then use new
to make sure the pointer has a dynamic life span (but remember, you will need to clean it up).
Update:
It seems the exception has the "auto delete" feature?
Not a thing.
I tried throwing a pointer to normal object (not inherited from exception).
There is nothing special about the exception object (or any of its derived classes). It is simply a normal object. Like all objects (that are a class), the destructor of the object is run when the object reaches the end of its lifetime. If A
does not have a destructor then the memory used by the object may not change (but it is not usable by other objects that are not your object).
But I can still access the object and its properties in the catch block.
That is the bad side of "Undefined Behavior". I may look like it is working. It's not working, it just looks like it is. And it is just as likely to not work on some other situation.