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.
Related
Try/catch block in C++ not being "caught."
I'm trying to have one catch block to get all exceptions.
#include <iostream>
#include <exception>
using namespace std;
int main()
{
try
{
throw 1;
}
catch (exception& e)
{
cout << "ERROR: " << e.what() << endl;
return 1;
}
return 0;
}
throw 1; will throw an int. As you do not catch an int, the exception goes uncaught, which is undefined behavior. Though it is possible to throw anything, always prefer to throw a class that derives from std::exception. You can catch an int with catch(int e) or catch(...), but there's really no reason to ever do that.
If you catch with catch(...), then you do not know the type of the object, so cannot access any members, properties, or other aspects, and so you cannot* gather any information about what was thrown. This should never be used.
*There are ways to get information about the thrown object, but it's far easier to just catch the right type in the first place
You are throwing an int, but only catching std::exception. Use a catch(...) to catch everything thrown.
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.
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
std::system_error handles exception with associated error code. Is it possible using common catch block to get std::system_error exception message and it's code? Like this
try{
// code generating exception
} catch (const std::exception& ex){ // catch all std::exception based exceptions
logger.log() << ex.what(); // get message and error code
// if exception type is system_error
}
Is the only way is to catch directly std::system_error type and get its code before base exception type catching? What is the best approach to use std::system_error widely?
What is the best approach to use std::system_error widely?
The best approach in my opinion, is to catch the exception directly.
catch (const std::system_error& e) {
std::cout << e.what() << '\n';
std::cout << e.code() << '\n';
} catch (const std::exception& e) {
std::cout << e.what() << '\n';
}
Is the only way is to catch directly std::system_error type and get its code before base exception type catching?
It's technically not the only way. It's the obvious and idiomatic way. You can use dynamic_cast.
catch (const std::exception& e) {
std::cout << e.what() << '\n';
auto se = dynamic_cast<const std::system_error*>(&e);
if(se != nullptr)
std::cout << se->code() << '\n';
}
But you mention in the comment that you prefer not to use dynamic_cast. It's possible to avoid that too, but not in any way that has any advantages.
Note that even if you can do things in non obvious ways, it doesn't mean that you should.
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
}
}