The Boost Exception framework is great. You can add information to an exception derived from std::exception and boost::exception at the appropriate level of an application, as described in the documentation.
But how can such information be added if you do not control the throw site in the code, e.g. the std lib throws an exception, e.g. map throws out_of_range?
It cannot be caught as boost::exception, because it does not derive from it:
try {
my_map.at(id);
} catch(boost::exception &e) { // NOT caught
e << errinfo_desc("id not found, map out of range");
throw;
}
It can be caught as std::exception because out_of_range derives from std::exception, but then no information can be added because it not a boost::exception:
try {
my_map.at(id);
} catch(std::exception &e) {
// compile error: e << errinfo_desc("id not found, map out of range");
throw;
}
Catching a std::exception and throwing a new boost::exception loses the original location of the exception which is not desired:
try {
my_map.at(id);
} catch(std::exception &e) {
BOOST_THROW_EXCEPTION(my_exception()
<< errinfo_desc("id not found, map out of range"));
}
Is is possible to preserve the original exception with its location etc. and still be able to add more information later? How?
Personally, I use the std::exception hierarchy wherever possible. And when they are not sufficient, then I just derive my exception class from std::exception. Never had any use case for boost::exception (perhaps all my code is too simple for that, don't know).
But if you really want to combine both, here is a wild idea: use multiple inheritance. Code sketch (untested, more like pseudocode):
// two personalities in one exception object
class MyException: public std::exception, public boost::exception {
explicit MyException(const std::exception& stdex) { ... }
... other ctors as needed...
... other stuff ...
};
...
try {
my_map.at(id);
} catch (const std::exception& stdex) {
MyException myex(stdex); // gets SOME of the std::exception information
myex << errinfo_desc("id not found, map out of range"); // boost::exception goodies
throw myex;
}
Obvious caveat: slicing issues when initialising MyException objects with a std::exception reference. And the usual problems with MI. You have been warned :-)
You can do this by catching both cases: boost::exception and std::exception
try {
my_map.at(id);
} catch(boost::exception &e) {
// If already a boost exception, catch here and add information
e << errinfo_desc("id not found, map out of range");
throw;
} catch(std::exception &) {
// Otherwise, catch here and convert to a boost exception
try { boost::rethrow_exception( boost::current_exception() ); }
catch( boost::exception& e ) {
e << errinfo_desc("id not found, map out of range");
throw;
}
}
If find it's a pain to write that much code, so I asked if there was a cleaner way of doing this: Adding error_info to std::exception
Related
I know the difference in handling of both of these catches, but what does it take for the ellipse to catch something the std::exception catch wouldn't catch?
For example:
try
{
throw std::runtime("runtime error!");
}
catch(const std::exception& e)
{
std::cout << "Exception: " << e;
}
catch(...)
{
std::cout << "How did I get here?";
throw;
}
I've seen examples of code that use both of these in conjunction, but I've not seen a reason you would do both.
catch(const std::exception& e)
Will catch std exceptions only.
catch(...)
Will catch everything there after.
You can handle integers and other types (http://www.cplusplus.com/doc/tutorial/exceptions/)
For example:
catch(int e)
While it's definitely a good idea to do so, you don't have to derive your custom exceptions from std::exception. C++ allows you to throw practically any object type.
So throw 1; will not be handled by your first handler, for example. And neither will...
class MyCustomException { // Doesn't derive
///
};
... if it was thrown.
You probably meant:
throw std::runtime_error("runtime error!"); // not std::runtime
The std::runtime_error is derived from the std::exception so your first catch block is fired up as it catches exceptions of type std::exception. And there you probably meant:
std::cout << "Exception: " << e.what(); // not e
If you threw anything else other than the std::run_time or std::exception and its derivatives, the second catch block would be triggered. Useful reading from the C++ FAQ:
What should I throw?
As written, the throw statement throws an object whose type is derived from std::exception, so it's caught by the first catch clause. If you change the throw to throw 3; the exception will be caught by the second catch clause, not the first.
I have a try-catch block like below
try
{
// Do something here.
}
catch (const std::exception &e)
{
// std exception.
}
catch(...)
{
// Unknown exception. We can't know the type.
}
I am reading some documentation from http://www.cplusplus.com/reference/exception/exception/ but to me it is not obvious how to know what exception type was caught when the code goes into the std::exception part.
Is there a way to get a string with the type of error? (I don't want to surface the error message, just the exception type)
Is there a way to get a string with the type of error?
Sort of. If you catch by reference (as you are doing in the above code), then you can apply typeid to the exception to get some info about its dynamic type. This is made possible by the fact that std::exception is a polymorphic type. However, there's no guarantee that std::type_info::name() is a readable name for the type.
You can catch different exceptions with different catch blocks:
try
{
// Do something here.
}
catch (const std::runtime_error& e)
{
// Handle runtime error
}
catch (const std::out_of_range& e)
{
// Handle out of range
}
catch (const std::exception &e)
{
// Handle all other exceptions
}
catch(...)
{
// Unknown exception. We can't know the type.
}
Of course it does not always make sense to have a seperate catch for every type of exception, so you still would need a way to tell what is the type of the exception within the catch(std::exception&) block, for which I refer you to this answer.
I know that in C++ you can catch an exception of any data type using:
try {
// throw exception here
} catch (...) {
// handle exception here
}
But I want to catch any C++ standard exception, such as std::logic_error, std::out_of_range, and not ones of other data types such as string or int. How can I catch only the C++ standard exceptions only? I want to call exp.what() on the passed in C++ standard exception object, and that's not possible using the above code.
All standard exceptions derive from std::exception, so catch that instead:
try {
// throw exception here
}
catch (const std::exception &e) {
// handle exception here
}
I am using QT 4.8 (C++) for desktop application project, and writing exception handling which is as follows :
void callerMethod()
{
try
{
method1();
}
catch(Exception1& e)
{
// display critcal error message
// abort application
}
catch(std::Exception& e)
{
// print exception error message
}
catch(...)
{
// print unknown exception message
}
}
void method1()
{
try
{
// some initializations
// some operations (here exceptions can occur)
// clean-up code (for successful operation i.e no exception occurred)
}
catch(Exception1& e)
{
// clean-up code
throw e;
}
catch(Exception2& e)
{
// clean-up code
throw e;
}
catch(Exception3& e)
{
// clean-up code
throw e;
}
catch(...)
{
// clean-up code
throw;
}
}
So my question do I need to write the clean-up code in every catch block?
Is there any way I can avoid writing repeated code?
NOTE:: [ In method1() ] I want to re-throw exceptions which occurred
to my caller.So I can not catch them in single catch block,
because then type information will be lost.
Method1 can be much simplified by two concepts:
RAII. Put any clean-up code into destructors, and the clean-up code will be centralized.
Use the unqualified throw, and you won't need to know about the type of exception thrown.
So, method1() should look like:
void method1()
{
// some initializations of RAII objects
// some operations (here exceptions can occur)
}
The first catch clause in callerMethod can be removed if you derive Exception1 from std::exception, since the what() method is virtual.
You should throw exceptions as low as possible and catch them as high as possible in the call chain. This automatically leads to less code duplication, and centralizes error handling. You are throwing/catching all in one place, which seems a bit ... forced.
I often do this kind of thing (especially for program-ending exceptions:
int main()
try
{
function_calls_that_may_throw();
// ...
}
catch(my_exception& e)
{
e.do_exception_stuff();
}
catch(std::exception& e)
{
std::cout << e.what();
}
catch(...)
{
std::cout << "Something bad happened.\n";
}
This is only possible for throwing exceptions you don't plan on handling better or retrying the failed operation or something.
The pro of this approach is that all/most error handling code is at the top-level of your program, and all the functions in the call chain don't have to worry one bit about this stuff, all they do is throw an exception when they feel like it.
If all your clean up code is totally identical, you can do everything in your catch (...) block:
try {
// code
} catch (...) {
// cleanup
throw;
}
If your code varies slightly, you can always call a cleanup function:
try {
// code
} catch (exc1 ex) {
cleanup(args);
// exc1 specific
throw;
} catch (exc2 ex) {
cleanup(args);
// exc2 specific
throw;
} catch (...) {
cleanup(args);
throw;
}
Which one should I use?
catch (_com_error e)
or
catch (_com_error& e)
The second. Here is my attempt at quoting Sutter
"Throw by value, catch by reference"
Learn to catch properly: Throw exceptions by value (not pointer) and
catch them by reference (usually to const). This is the combination
that meshes best with exception semantics. When rethrowing the same
exception, prefer just throw; to throw e;.
Here's the full Item 73. Throw by value, catch by reference.
The reason to avoid catching exceptions by value is that it implicitly makes a copy of the exception. If the exception is of a subclass, then information about it will be lost.
try { throw MyException ("error") }
catch (Exception e) {
/* Implies: Exception e (MyException ("error")) */
/* e is an instance of Exception, but not MyException */
}
Catching by reference avoids this issue by not copying the exception.
try { throw MyException ("error") }
catch (Exception& e) {
/* Implies: Exception &e = MyException ("error"); */
/* e is an instance of MyException */
}
Personally, I would go for the third option:
catch (const _com_error& e)
Also, note that, when using MFC, you may have to catch by pointer. Otherwise, #JaredPar's answer is the way you should normally go (and hopefully never have to deal with things that throw a pointer).
Definitely the second. If you had the following:
class my_exception : public exception
{
int my_exception_data;
};
void foo()
{
throw my_exception;
}
void bar()
{
try
{
foo();
}
catch (exception e)
{
// e is "sliced off" - you lose the "my_exception-ness" of the exception object
}
}