Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is catching an exception by reference dangerous?

Tags:

c++

exception

Please take a look at the following exception throwing and catching:

void some_function() {     // Was std::exception("message") in original post, which won't compile     throw std::runtime_error("some error message");  }  int main(int argc, char **argv) {     try {         some_function();     } catch (const std::exception& e) {         std::cerr << e.what() << std::endl;         exit(1);     }     return 0; } 

Is it safe to catch the thrown exception by reference?

My concern is because the exception e is actually placed on the stack of some_function(). But some_function() has just returned, causing e to be destructed. So actually now e points to a destructed object.

Is my concern correct?

What is the correct way to pass the exception without copying it by value? Should I throw new std::exception() so it is placed in the dynamic memory?

like image 991
SomethingSomething Avatar asked Oct 28 '15 09:10

SomethingSomething


People also ask

Why should exceptions be caught references?

An exception should be caught by reference rather than by value. The analyzer detected a potential error that has to do with catching an exception by value. It is much better and safer to catch exceptions by reference.

Is Catch exception bad?

Also when you catch all exceptions, you may get an exception that cannot deal with and prevent code that is upper in the stack to handle it properly. The general principal is to catch the most specific type you can. catch(Exception) is a bad practice because it catches all RuntimeException (unchecked exception) too.

What happens after catching an exception?

It is up to you to ensure that the application is recovered into a stable state after catching the exception. Usually it is achieved by "forgetting" whatever operation or change(s) produced the exception, and starting afresh on a higher level.

Should you catch all exceptions?

Generally, you should only catch exceptions that you know how to handle. The purpose of exceptions bubbling up is to allow other parts of the code catch them if they can handle them, so catching all exceptions at one level is probably not going to get you a desired result.


1 Answers

It is indeed safe - and recommended - to catch by const reference.

"e is actually placed on the stack of some_function()"

No it's not... the object actually thrown is created in an unspecified area of memory reserved for use by the exception handling mechanism:

[except.throw] 15.1/4: The memory for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1. The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr (18.8.5) that refers to the exception object is destroyed, whichever is later.

If a local variable is specified to throw, it's copied there-to if necessary (the optimiser may be able to directly create it in this other memory). That's why...

15.1/5 When the thrown object is a class object, the constructor selected for the copy-initialization and the destructor shall be accessible, even if the copy/move operation is elided (12.8).


If that's not clicked, it might help to imagine implementation vaguely like this:

// implementation support variable... thread__local alignas(alignof(std::max_align_t))     char __exception_object[EXCEPTION_OBJECT_BUFFER_SIZE];  void some_function() {     // throw std::exception("some error message");      // IMPLEMENTATION PSEUDO-CODE:     auto&& thrown = std::exception("some error message");     // copy-initialise __exception_object...     new (&__exception_object) decltype(thrown){ thrown };     throw __type_of(thrown);     // as stack unwinds, _type_of value in register or another     // thread_local var... }  int main(int argc, char **argv) {     try {         some_function();     } // IMPLEMENTATION:       // if thrown __type_of for std::exception or derived...       catch (const std::exception& e) {         // IMPLEMENTATION:         // e references *(std::exception*)(&__exception_object[0]);         ...     } } 
like image 128
Tony Delroy Avatar answered Sep 28 '22 17:09

Tony Delroy