I'm a student in my first C++ programming class, and I'm working on a project where we have to create multiple custom exception classes, and then in one of our event handlers, use a try/catch block to handle them appropriately.
My question is: How do I catch my multiple custom exceptions in my try/catch block? GetMessage() is a custom method in my exception classes that returns the exception explanation as a std::string. Below I've included all the relevant code from my project.
Thanks for your help!
try/catch block
// This is in one of my event handlers, newEnd is a wxTextCtrl
try {
first.ValidateData();
newEndT = first.ComputeEndTime();
*newEnd << newEndT;
}
catch (// don't know what do to here) {
wxMessageBox(_(e.GetMessage()),
_("Something Went Wrong!"),
wxOK | wxICON_INFORMATION, this);;
}
ValidateData() Method
void Time::ValidateData()
{
int startHours, startMins, endHours, endMins;
startHours = startTime / MINUTES_TO_HOURS;
startMins = startTime % MINUTES_TO_HOURS;
endHours = endTime / MINUTES_TO_HOURS;
endMins = endTime % MINUTES_TO_HOURS;
if (!(startHours <= HOURS_MAX && startHours >= HOURS_MIN))
throw new HourOutOfRangeException("Beginning Time Hour Out of Range!");
if (!(endHours <= HOURS_MAX && endHours >= HOURS_MIN))
throw new HourOutOfRangeException("Ending Time Hour Out of Range!");
if (!(startMins <= MINUTE_MAX && startMins >= MINUTE_MIN))
throw new MinuteOutOfRangeException("Starting Time Minute Out of Range!");
if (!(endMins <= MINUTE_MAX && endMins >= MINUTE_MIN))
throw new MinuteOutOfRangeException("Ending Time Minute Out of Range!");
if(!(timeDifference <= P_MAX && timeDifference >= P_MIN))
throw new PercentageOutOfRangeException("Percentage Change Out of Range!");
if (!(startTime < endTime))
throw new StartEndException("Start Time Cannot Be Less Than End Time!");
}
Just one of my custom exception classes, the others have the same structure as this one
class HourOutOfRangeException
{
public:
// param constructor
// initializes message to passed paramater
// preconditions - param will be a string
// postconditions - message will be initialized
// params a string
// no return type
HourOutOfRangeException(string pMessage) : message(pMessage) {}
// GetMessage is getter for var message
// params none
// preconditions - none
// postconditions - none
// returns string
string GetMessage() { return message; }
// destructor
~HourOutOfRangeException() {}
private:
string message;
};
If you have multiple exception types, and assuming there's a hierarchy of exceptions (and all derived publicly from some subclass of std::exception,) start from the most specific and continue to more general:
try
{
// throws something
}
catch ( const MostSpecificException& e )
{
// handle custom exception
}
catch ( const LessSpecificException& e )
{
// handle custom exception
}
catch ( const std::exception& e )
{
// standard exceptions
}
catch ( ... )
{
// everything else
}
On the other hand, if you are interested in just the error message - throw same exception, say std::runtime_error with different messages, and then catch that:
try
{
// code throws some subclass of std::exception
}
catch ( const std::exception& e )
{
std::cerr << "ERROR: " << e.what() << std::endl;
}
Also remember - throw by value, catch by [const] reference.
You should create a base exception class and have all of your specific exceptions derive from it:
class BaseException { };
class HourOutOfRangeException : public BaseException { };
class MinuteOutOfRangeException : public BaseException { };
You can then catch all of them in a single catch block:
catch (const BaseException& e) { }
If you want to be able to call GetMessage, you'll need to either:
place that logic into BaseException, or
make GetMessage a virtual member function in BaseException and override it in each of the derived exception classes.
You might also consider having your exceptions derive from one of the standard library exceptions, like std::runtime_error and use the idiomatic what() member function instead of GetMessage().
Another way to solve this problem when you don't have control on the class hierarchy of the exceptions and that you can't duplicate the contents of the catch block is using dynamic_cast Like this:
try
{
...
}
catch (std::exception& e)
{
if( nullptr == dynamic_cast<exception_type_1*> (&e)
&& nullptr == dynamic_cast<exception_type_2*> (&e))
{
throw;
}
// here you process the expected exception types
}
When templates can't, macros save the day.
The solution is taken from Boost. It boils to 7 lines of code.
/// #file multicatch.hpp
#include <boost/preprocessor/variadic/to_list.hpp>
#include <boost/preprocessor/list/for_each.hpp>
/// Callers must define CATCH_BODY(err) to handle the error,
/// they can redefine the CATCH itself, but it is not as convenient.
#define CATCH(R, _, T) \
catch (T & err) { \
CATCH_BODY(err) \
}
/// Generates catches for multiple exception types
/// with the same error handling body.
#define MULTICATCH(...) \
BOOST_PP_LIST_FOR_EACH(CATCH, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))
// end of file multicatch.hpp
/// #file app.cc
#include "multicatch.hpp"
// Contrived example.
/// Supply the error handling logic.
#define CATCH_BODY(err) \
log() << "External failure: " << err.what(); \
throw;
void foo() {
try {
bar(); // May throw three or more sibling or unrelated exceptions.
}
MULTICATCH(IOError, OutOfMemory)
}
#undef CATCH_BODY
Derive all of your exceptions from a common base class BaseException that has a virtual method GetMessage().
Then catch(const BaseException& e).
I had a similar problem today, but it turned out I didn't need my solution to solve my problem. Honestly, I couldn't think of real use cases (logging?), and I didn't find much use for it in my code.
Anyway, this is an approach with type lists (requires C++11). I think the advantage of this approach is that there's no need to have a common base class for custom exceptions (except for std::exception, maybe?). In other words, it is not intrusive to your exception hierarchy.
There might be some subtle errors that I am not aware of.
#include <type_traits>
#include <exception>
/// Helper class to handle multiple specific exception types
/// in cases when inheritance based approach would catch exceptions
/// that are not meant to be caught.
///
/// If the body of exception handling code is the same
/// for several exceptions,
/// these exceptions can be joined into one catch.
///
/// Only message data of the caught exception is provided.
///
/// #tparam T Exception types.
/// #tparam Ts At least one more exception type is required.
template <class T, class... Ts>
class MultiCatch;
/// Terminal case that holds the message.
/// ``void`` needs to be given as terminal explicitly.
template <>
class MultiCatch<void> {
protected:
explicit MultiCatch(const char* err_msg) : msg(err_msg) {}
const char* msg;
};
template <class T, class... Ts>
class MultiCatch : public MultiCatch<Ts...> {
static_assert(std::is_base_of<std::exception, T>::value, "Not an exception");
public:
using MultiCatch<Ts...>::MultiCatch;
/// Implicit conversion from the guest exception.
MultiCatch(const T& error) : MultiCatch<Ts...>(error.what()) {} // NOLINT
/// #returns The message of the original exception.
const char* what() const noexcept {
return MultiCatch<void>::msg;
}
};
/// To avoid explicit ``void`` in the type list.
template <class... Ts>
using OneOf = MultiCatch<Ts..., void>;
/// Contrived example.
void foo() {
try {
bar(); // May throw three or more sibling or unrelated exceptions.
} catch (const OneOf<IOError, OutOfMemory>& err) {
log() << "External failure: " << err.what();
throw; // Throw the original exception.
}
}
I run into the same problem and here is what I ended up with:
std::shared_ptr<MappedImage> MappedImage::get(const std::string & image_dir,
const std::string & name,
const Packet::Checksum & checksum) {
try {
return std::shared_ptr<MappedImage>(images_.at(checksum));
} catch (std::out_of_range) {
} catch (std::bad_weak_ptr) {
}
std::shared_ptr<MappedImage> img =
std::make_shared<MappedImage>(image_dir, name, checksum);
images_[checksum_] = img;
return img;
}
In my case the function returns when it doesn't get an exception. So I don't actually have to do anything inside the catch but can do the work outside the try.
#include <iostream>
void test(int x)`
{
try{
if(x==1)
throw (1);
else if(x==2)
throw (2.0);
}
catch(int a)
{
cout<<"It's Integer";
}
catch(double b)
{
cout<<"it's Double";
}
}
int main(){
cout<<" x=1";
test(1);
cout<<"X=2";
test(2.0);
return 0;
}`
Related
Header file:
#ifndef MUTEXCLASS
#define MUTEXCLASS
#include <pthread.h>
class MutexClass
{
private:
pthread_mutex_t & _mutexVariable;
public:
MutexClass (pthread_mutex_t &);
~MutexClass ();
};
#endif // MUTEXCLASS
Source file:
#include "mutexClass.h"
#include <stdexcept>
MutexClass::MutexClass (pthread_mutex_t & arg) : _mutexVariable (arg)
{
_mutexVariable = PTHREAD_MUTEX_INITIALIZER;
int returnValue = pthread_mutex_lock (&_mutexVariable);
if (returnValue > 0)
{
throw std::logic_error ("Mutex couldn't be locked!");
}
}
MutexClass::~MutexClass()
{
pthread_mutex_unlock (&_mutexVariable);
}
Where am I supposed to catch the exception thrown in the constructor?
An exception thrown in a constructor can be handled
by the code explicitly creating the object (try { MutexClass m; ... } catch(const std::logic_error& e) { ... })
by code creating an object that contains as member a MutexClass instance (including as base sub-object... i.e. by code that creates an object derived from MutexClass)
by code calling code doing the creation as exceptions will un-wind the stack until some code handles them
Note that for exceptions thrown in constructor of objects that are members of bigger objects (either for an has-a or a is-a relationship) there is a tricky part. The destructor of the bigger object will not be called if the costruction of a member throws an exception... only the already constructed members will be destroyed before propagating the exception. For example a class like:
struct Foo {
MyData * data;
MutexClass m;
MyData() : data(new int[1000]) { }
~MyData() { delete[] data; } // NOT called if m constructor throws
};
will leak memory if MutexClass constructor throws an exception.
Also before writing an exception handler however ask yourself if catching the exception is the right thing to do (i.e. if you know what to do when that condition occurs). Catching an exception and "hiding" it because you don't know what to do in that case is the worst possible choice.
In the specific case if you cannot lock a freshly created mutex can you expect the system to be still in good enough shape that keeping it running is a good idea?
As with any exception, anywhere up the stack where you can handle the exception. This is no way different from handling exceptions thrown in functions.
At the point of construction
try {
MutexClass m(arg);
}catch( std::logic_error const & e)
{
}
or if you have a pointer
try {
MutexClass * m = new MutexClass(arg);
}catch( std::logic_error const & e)
{
}
If you were able work with a pointer , passed to a function , surround the function.
E.g.
void funfun ( MutexClass * );
try {
funfun(new MutexClass(arg));
}catch( std::logic_error const & e)
{
}
If you are going to construct the object in an initializer list:
class A
{
MutexClass mc;
A(pthread_mutex_t & m) try : mc(m)
{
} catch ( std::logic_error const & e )
{
// do something here to handle the failure
// of mc(m) and the now the failure of A
// must be handled in the construction point of A
}
};
But now you have to handle the failure of the constructor of A as well.
Furthermore you should watch out for implicit conversions and copies, and you class is sadly copiable.
void funfun(MutexClass m );
pthread_mutex & m;
try
{
void funfun(m);
} catch( std::logic_error const & e )
{
}
Read before throwing from a constructor.
Also don't forget that such constructors are not good as static members.
So this type of class may break your program
class maybreak
{
private:
static MutexClass mc;
// ....
};
unless a wrapper function method is defined to put the construction of the static after your program actually starts (COFU).
in this particular program I implemented a deque. the only problem seems to be my error handling. here is the relevant code:
#include <exception>
class Deque {
public:
class RemoveError : exception {
public:
virtual const char* what() const noexcept {
return "error: cannot remove element; the queue is empty";
}
}R_error;
T removeFirst() throw(RemoveError);
};
Deque::removeFirst() throw(RemoveError) {
if (isEmpty())
{ throw R_error; }
}
int main () {
try {
Deque Q;
printf ( "this should be an error :%d\n", Q.removeFirst ( ) );
}
catch(exception& e) {
printf ( e.what(), '\n');
}
}
and yet, when I deliberately try to remove one too many nodes from my deque, the error on the screen is
terminate called after throwing an instance of 'Deque::RemoveError
instead of
error: cannot remove element; the queue is empty
I have tried both using and not using the virtual in my what() function, and I tried throwing RemoveError() instead of R_error.
is there any reason this is happening? I tried to find an answer on here but couldn't find this particular problem.
edit: as noted below, I had my exceptions private; changing
class RemoveError : exception {
to either
struct RemoveError : exception {
class RemoveError : public exception {
fixed it. Thanks everyone for your help
That error message gets produced by g++ default uncaught exception handler, see Verbose Terminate Handler:
The __verbose_terminate_handler function obtains the name of the current exception, attempts to demangle it, and prints it to stderr. If the exception is derived from exception then the output from what() will be included.
But in:
class RemoveError : exception
std::exception is not a public base class of RemoveError, hence that exception handler cannot call its what function.
Fix:
class RemoveError : public exception
Or:
struct RemoveError : exception
Note 1:
virtual const char* what() const noexcept
Should be:
const char* what() const noexcept override
Note 2:
T removeFirst() throw(RemoveError);
Exception specification is depricated in C++11. That should be just plain:
T removeFirst();
terminate called after throwing an instance of
'Deque::RemoveError'
std::terminate was called as there was an active exception that, through stack unwinding, was not caught.
In order to retrieve the message thrown along with the exception you have to catch the exception somewhere and call what.
{
try {
// code that might throw
} catch(RemoveError e) {
std::cerr << e.what() << std::endl;
}
}
I have a class that manages resources. It takes a Loader class that can retrieve the resource from a path. Loader is an abstract base class, so anyone could make a new loader.
If a resource is requested that is not in the cache, the resource manager will request it from the loader. If the loader fails, resource manager throws an exception class I made called LoadingError.
I want the Loader class to throw exceptions when it fails. I can require them to inherit from my own exception base class if necessary.
The problem is, when LoadingError is thrown, I want it to include specific information about why it failed. But I don't know exactly what exceptions may be thrown by the Loader. (The user might, in his catch blocks around the resource manager).
Either I can throw only LoadingError with some general information, or allow a specific exception from Loader come out and not touch it. But I would like to catch the exception and bundle it in my own LoadingError exception, or point to it in LoadingError . But I don't know how long the pointed-to exception will last (concerned about bad pointer).
Which of the three should I do? (And how, for the third one..)
Thanks
How about a nested exception?
try { /* ... */ }
catch (...)
{
throw MyException("An error occurred", std::current_exception());
}
Just make a suitable class that stores the exception:
struct MyException : std::exception
{
std::string message;
std::exception_ptr nested_exception;
MyException(std::string m, std::exception_ptr e)
: message(std::move(m))
, nested_exception(std::move(e))
{ }
// ...
};
When the exception is caught, the catcher can rethrow the nested exception:
try { /* load resource */ }
catch (MyException & e)
{
log("Resource loading failed: " + e.what());
std::rethrow_exception(e.nested_exception);
}
In fact, this entire logic is already provided by the standard library via std::throw_with_nested.
When one can enforce use of one's own exception classes throughout the code, the simplest way to do nested exception is undoubtedly to just define a custom exception class that contains a std::exception_ptr, which can be obtained via std::current_exception, both declared by the <exception> header.
However, C++11 supports nested exceptions via the std::nested_exception class, and functions such as std::throw_with_nested. The nested_exception constructor picks up the ? current_exception()`, if any, and stores that as its nested exception. There's no way to specify the nested exception expclitly: it's always the current exception.
This machinery also supports exception propagation through non-exception-aware code such as up through C callbacks, and it supports exceptions (and nested exceptions) of arbitrary classes, not just std::exception and derived classes.
So, when e.g. library code uses this functionality, then it's desirable to be able to deal with such standard nested exceptions, and not just one's own custom (simpler to use but less general) scheme.
Sadly, as I'm writing this (Jan 2014) the Visual C++ compiler does not yet support std::nested_exception, although it does support much of the rest of the machinery. Happily, it's not difficult to define these things. E.g., googling it, I found working code at Tomaka-17's blog, and that's the code that I've adapted below -- std::nested_exception support for Visual C++:
#include <exception> // std::rethrow_exception
// For Visual C++ define CPPX_NORETURN as "__declspec(noreturn)"
#ifndef CPPX_NORETURN
# define CPPX_NORETURN [[noreturn]]
#endif
// Visual C++ 12.0 lacks these things.
// Code adapted from http://blog.tomaka17.com/2013/07/c11-nested-exceptions/.
#if !defined( GOOD_COMPILER )
#include <utility> // std::forward
#include <type_traits> // std::remove_reference
namespace std {
class nested_exception
{
private:
exception_ptr nested;
public:
CPPX_NORETURN
void rethrow_nested() const
{ rethrow_exception(nested); }
exception_ptr nested_ptr() const { return nested; }
virtual ~nested_exception() {}
nested_exception() : nested( current_exception() ) {}
};
template< class Type >
CPPX_NORETURN
void throw_with_nested( Type&& t )
{
typedef remove_reference<Type>::type Pure_type;
struct Unspecified_mi_type
: nested_exception
, Pure_type
{
Unspecified_mi_type( Type&& t )
: Pure_type( forward<Type>( t ) )
{}
};
if (is_base_of<nested_exception, Pure_type>::value)
{
throw forward<Type>( t );
}
else
{
throw Unspecified_mi_type( forward<Type>( t ) );
}
}
template< class X >
void rethrow_if_nested( X const& x )
{
if( auto const ptr = dynamic_cast< nested_exception const* >( &x ) )
{
ptr->rethrow_nested(); // It's specified to do this, C++11 §18.8/8.
}
}
}
#endif // not GOOD_COMPILER
With g++ 4.7.2 it would be more involved to define this stuff, but since g++ 4.8.2 already has it it's not necessary: for g++ just upgrade the compiler if necessary.
Then the next problem is how to retrieve the nested exception information.
Essentially that boils down to iteratively rethrowing and catching each nested exception, e.g. as follows:
#include <iostream>
#include <stdexcept> // std::runtime_error
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS
struct Loader { virtual void load() = 0; };
struct Resource_manager
{
Loader& loader;
void foo()
{
try
{
loader.load();
}
catch( ... )
{
std::throw_with_nested( std::runtime_error( "Resource_manager::foo failed" ) );
}
}
Resource_manager( Loader& a_loader )
: loader( a_loader )
{}
};
int main()
{
using std::cerr; using std::endl;
struct Failing_loader
: Loader
{
virtual void load() override { throw std::runtime_error( "Loading failed"); }
};
try
{
Failing_loader loader;
Resource_manager rm( loader );
rm.foo();
return EXIT_SUCCESS;
}
catch( ... )
{
bool is_cause = false;
for( auto px = std::current_exception(); px != nullptr; )
{
try
{
std::rethrow_exception( px );
}
catch( std::exception const& x )
{
cerr << "!" << (is_cause? "<because> " : "") << x.what() << endl;
px = nullptr;
if( auto pnx = dynamic_cast< std::nested_exception const* >( &x ) )
{
px = pnx->nested_ptr();
}
}
catch( ... )
{
cerr << (is_cause? "!<because of an " : "!<") << "unknown failure>" << endl;
px = nullptr;
}
is_cause = true;
}
}
return EXIT_FAILURE;
}
Output:
!Resource_manager::foo failed
!<because> Loading failed
Disclaimer: I cooked up the above code for this answer, so it's not been extensively tested. But anyway, enjoy!
I have a class that manages resources. It takes a Loader class that can retrieve the resource from a path. Loader is an abstract base class, so anyone could make a new loader.
If a resource is requested that is not in the cache, the resource manager will request it from the loader. If the loader fails, resource manager throws an exception class I made called LoadingError.
I want the Loader class to throw exceptions when it fails. I can require them to inherit from my own exception base class if necessary.
The problem is, when LoadingError is thrown, I want it to include specific information about why it failed. But I don't know exactly what exceptions may be thrown by the Loader. (The user might, in his catch blocks around the resource manager).
Either I can throw only LoadingError with some general information, or allow a specific exception from Loader come out and not touch it. But I would like to catch the exception and bundle it in my own LoadingError exception, or point to it in LoadingError . But I don't know how long the pointed-to exception will last (concerned about bad pointer).
Which of the three should I do? (And how, for the third one..)
Thanks
How about a nested exception?
try { /* ... */ }
catch (...)
{
throw MyException("An error occurred", std::current_exception());
}
Just make a suitable class that stores the exception:
struct MyException : std::exception
{
std::string message;
std::exception_ptr nested_exception;
MyException(std::string m, std::exception_ptr e)
: message(std::move(m))
, nested_exception(std::move(e))
{ }
// ...
};
When the exception is caught, the catcher can rethrow the nested exception:
try { /* load resource */ }
catch (MyException & e)
{
log("Resource loading failed: " + e.what());
std::rethrow_exception(e.nested_exception);
}
In fact, this entire logic is already provided by the standard library via std::throw_with_nested.
When one can enforce use of one's own exception classes throughout the code, the simplest way to do nested exception is undoubtedly to just define a custom exception class that contains a std::exception_ptr, which can be obtained via std::current_exception, both declared by the <exception> header.
However, C++11 supports nested exceptions via the std::nested_exception class, and functions such as std::throw_with_nested. The nested_exception constructor picks up the ? current_exception()`, if any, and stores that as its nested exception. There's no way to specify the nested exception expclitly: it's always the current exception.
This machinery also supports exception propagation through non-exception-aware code such as up through C callbacks, and it supports exceptions (and nested exceptions) of arbitrary classes, not just std::exception and derived classes.
So, when e.g. library code uses this functionality, then it's desirable to be able to deal with such standard nested exceptions, and not just one's own custom (simpler to use but less general) scheme.
Sadly, as I'm writing this (Jan 2014) the Visual C++ compiler does not yet support std::nested_exception, although it does support much of the rest of the machinery. Happily, it's not difficult to define these things. E.g., googling it, I found working code at Tomaka-17's blog, and that's the code that I've adapted below -- std::nested_exception support for Visual C++:
#include <exception> // std::rethrow_exception
// For Visual C++ define CPPX_NORETURN as "__declspec(noreturn)"
#ifndef CPPX_NORETURN
# define CPPX_NORETURN [[noreturn]]
#endif
// Visual C++ 12.0 lacks these things.
// Code adapted from http://blog.tomaka17.com/2013/07/c11-nested-exceptions/.
#if !defined( GOOD_COMPILER )
#include <utility> // std::forward
#include <type_traits> // std::remove_reference
namespace std {
class nested_exception
{
private:
exception_ptr nested;
public:
CPPX_NORETURN
void rethrow_nested() const
{ rethrow_exception(nested); }
exception_ptr nested_ptr() const { return nested; }
virtual ~nested_exception() {}
nested_exception() : nested( current_exception() ) {}
};
template< class Type >
CPPX_NORETURN
void throw_with_nested( Type&& t )
{
typedef remove_reference<Type>::type Pure_type;
struct Unspecified_mi_type
: nested_exception
, Pure_type
{
Unspecified_mi_type( Type&& t )
: Pure_type( forward<Type>( t ) )
{}
};
if (is_base_of<nested_exception, Pure_type>::value)
{
throw forward<Type>( t );
}
else
{
throw Unspecified_mi_type( forward<Type>( t ) );
}
}
template< class X >
void rethrow_if_nested( X const& x )
{
if( auto const ptr = dynamic_cast< nested_exception const* >( &x ) )
{
ptr->rethrow_nested(); // It's specified to do this, C++11 §18.8/8.
}
}
}
#endif // not GOOD_COMPILER
With g++ 4.7.2 it would be more involved to define this stuff, but since g++ 4.8.2 already has it it's not necessary: for g++ just upgrade the compiler if necessary.
Then the next problem is how to retrieve the nested exception information.
Essentially that boils down to iteratively rethrowing and catching each nested exception, e.g. as follows:
#include <iostream>
#include <stdexcept> // std::runtime_error
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS
struct Loader { virtual void load() = 0; };
struct Resource_manager
{
Loader& loader;
void foo()
{
try
{
loader.load();
}
catch( ... )
{
std::throw_with_nested( std::runtime_error( "Resource_manager::foo failed" ) );
}
}
Resource_manager( Loader& a_loader )
: loader( a_loader )
{}
};
int main()
{
using std::cerr; using std::endl;
struct Failing_loader
: Loader
{
virtual void load() override { throw std::runtime_error( "Loading failed"); }
};
try
{
Failing_loader loader;
Resource_manager rm( loader );
rm.foo();
return EXIT_SUCCESS;
}
catch( ... )
{
bool is_cause = false;
for( auto px = std::current_exception(); px != nullptr; )
{
try
{
std::rethrow_exception( px );
}
catch( std::exception const& x )
{
cerr << "!" << (is_cause? "<because> " : "") << x.what() << endl;
px = nullptr;
if( auto pnx = dynamic_cast< std::nested_exception const* >( &x ) )
{
px = pnx->nested_ptr();
}
}
catch( ... )
{
cerr << (is_cause? "!<because of an " : "!<") << "unknown failure>" << endl;
px = nullptr;
}
is_cause = true;
}
}
return EXIT_FAILURE;
}
Output:
!Resource_manager::foo failed
!<because> Loading failed
Disclaimer: I cooked up the above code for this answer, so it's not been extensively tested. But anyway, enjoy!
I have recently started using boost::exception. Now I would like to use boost::errinfo_nested_exception to print information about the cause of the error. The problem is I can't figure out how to get information from the cause. I have tried the following with no success:
#include <iostream>
#include <boost/exception/all.hpp>
struct myex : public virtual boost::exception {};
int main()
{
myex cause;
cause << boost::errinfo_file_name("causefile.cpp");
try {
myex ex;
ex << boost::errinfo_nested_exception(boost::copy_exception(cause));
throw ex;
}
catch (myex& e) {
// Here I would like to extract file name from cause and print
// it in a nice way, but I cant figure out what to do with a
// boost::exception_ptr.
const boost::exception_ptr* c =
boost::get_error_info<boost::errinfo_nested_exception>(e);
// I cant do this:
// const std::string* file = boost::get_error_info<boost::errinfo_file_name>(*c);
// Nor this:
// const std::string* file = boost::get_error_info<boost::errinfo_file_name>(**c);
// This works fine and the nested exception is there, but that's not what I want.
std::cout << boost::diagnostic_information(e) << std::endl;
}
return 0;
}
You need to rethrow the nested exception and examine that:
const boost::exception_ptr* c =
boost::get_error_info<boost::errinfo_nested_exception>(e);
if(c) try {
boost::rethrow_exception(*c);
} catch(boost::exception const& e) { // or a type derived from it
const std::string* file = boost::get_error_info<boost::errinfo_file_name>(e);
// ...
} catch(...) {
// presumably you don't want the exception to escape if it is
// not derived from boost::exception
}
I personally use a get_error_info wrapper that returns the result of boost::get_error_info<some_error_info>(e), or if nothing is found the result of get_error_info<some_error_info>(nested) (recursive call here) or 0 if there is no nested exception (or it is not error_info-enabled).
Alternatively/as a complement, you can factor the checking code above (the different catch clauses) in a function:
std::string const* // or return a tuple of what you examined etc.
examine_exception()
{
try {
throw; // precondition: an exception is active
} catch(boost::exception const& e) {
// as above
return ...;
}
}
boost::diagnostic_information is the correct way to get a description afaik.
But you could also overload to_string for boost::error_info(T):
http://svn.boost.org/svn/boost/trunk/boost/exception/errinfo_errno.hpp