This question is similar to c++ Exception Class Design and follows:
I want to design exception class hierarchy for my application and here are the design points I used:
Exception should be derived from standard exception classes (those are std::exception, std::logic_error and std::runtime_error).
Exception class should be able to take error description (i.e. what is called what) and position where it occurred (const std::string &file, int line)
Exception should not throw any exception during construction or from any other member.
Given this I have:
#define throw_line(TException, what) throw TException((what), __FILE__, __LINE__)
class AnException : public std::exception {
public:
AnException(const std::string &what, const std::string &file, int line) noexcept {
try {
what_ = what;
file_ = file;
line_ = line;
} catch (std::exception &e) {
was_exception_ = true;
}
}
virtual ~AnException() noexcept {}
virtual const char *what() const noexcept override {
if (was_exception_) {
return "Exception occurred while construct this exception. No further information is available."
} else {
try {
std::string message = what_ + " at " + file_ + ":" + std::to_string(line);
return message.c_str();
} catch (std::exception &e) {
return "Exception occurred while construct this exception. No further information is available."
}
}
}
};
class ParticularException : public AnException {
...
}
As you can see, it appears to be somewhat complex to construct such class, because we definitely should not have exceptions in constructor (otherwise std::terminate() will be called) or in what() member.
The question: is this example of a good design or I should remove some restrictions (like, having file/line information) to simplify it? Is there a better way?
I'm free to use C++11/C++14, but trying to keep off C++17 since it is not yet finished and compilers may not fully implement it.
Note: I want this code to be cross-platform.
Thanks in advance.
Edit 1: The follow up question: how can I retire file/line information, but keep that in logs? May be printing stacktrace is a better solution than what I have now? I mean leave exception class which just holds an error message (what) and call something like print_backtrace on upper level of exception handling chain.
Relating to my comment, depending on whether a what literal is acceptable, I had something like this in mind:
#include <array>
template <int N> constexpr std::size_t arraySize(const char (&)[N]){return N;}
template <class ExceptT, std::size_t whatN, std::size_t fileN>
class MyExcept : public ExceptT
{
static_assert(std::is_base_of<std::exception, ExceptT>::value, "bad not base");
public:
MyExcept(
const char (&what)[whatN],
const char (&file)[fileN],
int line) noexcept
: ExceptT(""), //Using our own what
what_(), file_(), line_(line)
{
std::copy(std::begin(what), std::end(what), begin(what_));
std::copy(std::begin(file), std::end(file), begin(file_));
}
virtual const char *what() const noexcept override
{
//....
}
private:
std::array<char,whatN> what_;
std::array<char,fileN> file_;
int line_;
};
#define throw_line(TException, what) throw MyExcept<TException,arraySize(what),arraySize(__FILE__)>(what,__FILE__, __LINE__)
void driver()
{
throw_line(std::runtime_error, "Hoo hah");
}
I've added some code that allows deriving from a std::exception type (type requires constructor with single literal argument (could check that this is also noexcept). I'm passing it an empty string literal, so std::exception class should at least not throw. I'm using static_assert to check this.
it cannot throw on construction...
it derives from std::exception...
it contains "fixed" what and position
This usually happens only, if you want to catch certain errors in another catch-block than your most outer catch block. I would only start doing this, if I see a demand. I remember that my system-call-read() wrapper would throw a different exception for EOF -- since this sometimes need to be caught.
Then I've got a system-error-exception and a normal message exception, since std::exception does not store any message with certain compilers.
Separate classes for exceptions are overused in the same way throw-specifications were overused.
Please remember that if you want to catch a certain error somewhere else than in the outer-most-catch-block, you need to be able to do something about the error, other than re-throw it. Usually the string returned from what() should already be sufficient to tell you what kind of error occurred. Thus for printing reasons there is no need to overload the exception type.
Related
This is an example of what I often do when I want to add some information to an exception:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Is there a nicer way to do it?
The standard exceptions can be constructed from a std::string:
#include <stdexcept>
char const * configfile = "hardcode.cfg";
std::string const anotherfile = get_file();
throw std::runtime_error(std::string("Failed: ") + configfile);
throw std::runtime_error("Error: " + anotherfile);
Note that the base class std::exception can not be constructed thus; you have to use one of the concrete, derived classes.
Here is my solution:
#include <stdexcept>
#include <sstream>
class Formatter
{
public:
Formatter() {}
~Formatter() {}
template <typename Type>
Formatter & operator << (const Type & value)
{
stream_ << value;
return *this;
}
std::string str() const { return stream_.str(); }
operator std::string () const { return stream_.str(); }
enum ConvertToString
{
to_str
};
std::string operator >> (ConvertToString) { return stream_.str(); }
private:
std::stringstream stream_;
Formatter(const Formatter &);
Formatter & operator = (Formatter &);
};
Example:
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData); // implicitly cast to std::string
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData >> Formatter::to_str); // explicitly cast to std::string
There are different exceptions such as runtime_error, range_error, overflow_error, logic_error, etc.. You need to pass the string into its constructor, and you can concatenate whatever you want to your message. That's just a string operation.
std::string errorMessage = std::string("Error: on file ")+fileName;
throw std::runtime_error(errorMessage);
You can also use boost::format like this:
throw std::runtime_error(boost::format("Error processing file %1") % fileName);
The following class might come quite handy:
struct Error : std::exception
{
char text[1000];
Error(char const* fmt, ...) __attribute__((format(printf,2,3))) {
va_list ap;
va_start(ap, fmt);
vsnprintf(text, sizeof text, fmt, ap);
va_end(ap);
}
char const* what() const throw() { return text; }
};
Usage example:
throw Error("Could not load config file '%s'", configfile.c_str());
Use string literal operator if C++14 (operator ""s)
using namespace std::string_literals;
throw std::exception("Could not load config file '"s + configfile + "'"s);
or define your own if in C++11. For instance
std::string operator ""_s(const char * str, std::size_t len) {
return std::string(str, str + len);
}
Your throw statement will then look like this
throw std::exception("Could not load config file '"_s + configfile + "'"_s);
which looks nice and clean.
Maybe this?
throw std::runtime_error(
(std::ostringstream()
<< "Could not load config file '"
<< configfile
<< "'"
).str()
);
It creates a temporary ostringstream, calls the << operators as necessary and then you wrap that in round brackets and call the .str() function on the evaluated result (which is an ostringstream) to pass a temporary std::string to the constructor of runtime_error.
Note: the ostringstream and the string are r-value temporaries and so go out of scope after this line ends. Your exception object's constructor MUST take the input string using either copy or (better) move semantics.
Additional: I don't necessarily consider this approach "best practice", but it does work and can be used at a pinch. One of the biggest issues is that this method requires heap allocations and so the operator << can throw. You probably don't want that happening; however, if your get into that state your probably have way more issues to worry about!
There are two points to answer in regards to what you want:
1.
The first point is that the nicer way is creating special types (classes) for custom exceptions and passing parameters as fields of the classes.
Something like the following:
class BaseFor_Exceptions : public std::exception {
protected:
BaseFor_Exceptions();
};
class Exception1 : public BaseFor_Exceptions {
public:
Exception1(uint32_t value1);
private:
uint32_t value1;
};
throw Exception1(0);
The second point is that you are performing memory allocations when preparing the exception object because of trying to pass a value of variable size (filename).
There is a possibility (when changing objects of the both std::string and std::stringstream ) of std::bad_alloc exception to be thrown in the process of it, so that you fail to prepare or throw (*) your exception – you will lose the info and the state.
In a well-designed program it is easy to avoid memory allocation when preparing or handling an exception. All that you need is just:
either guarantee the value is still life when handling the exception and pass some kind of link to the value as a part of the exception – either reference or some kind (most likely smart) of pointer,
or get the value when handling the exception using the exception type info or/and fixed-size values;
for example,
} catch (const ConfigurationLoadError & ex) {
std::cerr
<< “Some message 1 ”
<< serviceLocator1.SomeGetMethod1().Get_ConfigurationFileName();
} catch (const SomeException & ex) {
std::cerr
<< “Some message 2 ”
<< serviceLocator1.SomeGetMethod2().GetEventDetailsString(ex.Get_Value1());
}
Of course, you always have an option to accept buffer size limitations and use a pre-allocated buffer.
Also, please note that the type (classes) used for exceptions are not permitted to throw exceptions out of their copy constructors since, if the initial exception is attempted to be caught by value, a call of copy constructor is possible (in case is not elided by the compiler) and this additional exception will interrupt the initial exception handling before the initial exception is caught, which causes calling std::terminate.
Since C++11 compilers are permitted to eliminate the copying in some cases when catching, but both the elision is not always sensible and, if sensible, it is only permission but not obligation (see https://en.cppreference.com/w/cpp/language/copy_elision for details; before C++11 the standards of the language didn’t regulate the matter).
'*' Also, you should avoid exceptions (will call them the additional) to be thrown out of constructors and move constructors of your types (classes) used for exceptions (will call them initial) since the constructors and move constructors could be called when throwing objects of the types as initial exceptions, then throwing out an additional exception would prevent creation of an initial exception object, and the initial would just be lost. As well as an additional exception from a copy constructor, when throwing an initial one, would cause the same.
Ran into a similar issue, in that creating custom error messages for my custom exceptions make ugly code. This was my solution:
class MyRunTimeException: public std::runtime_error
{
public:
MyRunTimeException(const std::string &filename):std::runtime_error(GetMessage(filename)) {}
private:
static std::string GetMessage(const std::string &filename)
{
// Do your message formatting here.
// The benefit of returning std::string, is that the compiler will make sure the buffer is good for the length of the constructor call
// You can use a local std::ostringstream here, and return os.str()
// Without worrying that the memory is out of scope. It'll get copied
// You also can create multiple GetMessage functions that take all sorts of objects and add multiple constructors for your exception
}
}
This separates the logic for creating the messages. I had originally thought about overriding what(), but then you have to capture your message somewhere. std::runtime_error already has an internal buffer.
Whenever I need a custom message to be thrown in an exception, I construct a C-style string with snprintf() and pass it to the exception constructor.
if (problem_occurred) {
char buffer[200];
snprintf(buffer, 200, "Could not load config file %s", configfile);
string error_mesg(buffer);
throw std::runtime_error(error_mesg);
}
I'm not sure if the extra string string error_mesg(buffer) is necessary. I reason that the buffer is on stack memory, and if the exception catcher keeps running, then allowing the catcher to keep a reference to a stack-allocated C string is problematic. Instead, passing a string to the exception will invoke copy-by-value, and the buffer array will be deep-copied.
This is a (modified) problem from a test last week.
I was given an exception class with a predefined number in it:
class ErrorException {
/**
* Stub class.
*/
private :static long ErrorCode;
public: ErrorException( string str) {
cout <<str;
}
};
long ErrorException::ErrorCode = -444;
I think I was supposed to do was catch the exception and then return the number as an error code, but I could not figure out how to get the number in. I could make the catch return a string but not the number as string:
#include "stdafx.h"
#include <iostream>
#include "ErrorException.h"
#include "errno.h""
#include <string>;
class FillerFunction {
public :
virtual int getFillerFunction(int x) throw (ErrorException) = 0;
} // this notation means getFillerFunction is always throwing ErrorException?
double calculateNumber(int y){
//.....
try{
if (y !=0){
throw(ErrorException(?????))
}
};
double catchError(){
catch(ErrorException& x);
};
I eventually made it return the string "error" which is no better than using an if statement. I've looked up other catch-throw examples in c++ and dynamic exceptions, but I can't find an example with an exception grabbing a variable defined in the class.How do I access the ErrorCode, save changing the return type of ErrorException()?
Though this question has already been answered, I just want to add a few notes on proper exception handling in C++11:
First, throw(ErrorException) should not be used, as it is deprecated: http://en.cppreference.com/w/cpp/language/except_spec
Also, it is generally advisable to make use of the fact that C++ provides standard exception classes, personally I usually derive from std::runtime_error.
In order to really take advantage of the exception mechanism in C++11, I recommend using std::nested_exception and std::throw_with_nested as described on StackOverflow here and here. Creating a proper exception handler will allow you to get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging. Since you can do this with your derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
In your throw you're constructing an exception object. If you prefer to pass a number, you must provide the appropriate constructor.
Quick and dirty:
class ErrorException {
private :
static long ErrorCode;
public:
ErrorException( string str) {
cerr <<str<<endl;
}
ErrorException( long mynumeric code) {
cerr <<"error "<<mynumericcode<<endl;
}
};
The catching should look like:
double calculateNumber(int y){
try {
if (y !=0){
throw(ErrorException(227));
}
} catch(ErrorException& x) {
cout << "Error catched"<<endl;
}
}
Must be elaborated further
It's unusual to to print something in the exception constructor. You'd better populate the information needed in the catch, so that these information could later be accessed with the appropriate getter. The printing would then occur in the exception handler.
If you have a static error code, I suppose that somewhere you have a function that returns the last error code whatever happened. So maybe you'd update this code (but how do you intend to update it with the existing string alternative ?
Here how it could look like:
class ErrorException {
private :
static long LastErrorCode;
long ErrorCode;
string ErrorMessage;
public:
ErrorException(long ec, string str) : ErrorCode(ec), ErrorMessage(str)
{
LastErrorCode = ec;
}
static long getLastError() const { return LastErrorCode; } // would never be reset
long getError() const { return ErrorCode; }
string getMessage() const { return ErrorMessage; }
};
The catching should look like:
double calculateNumber(int y){
try {
if (y !=0){
throw(ErrorException(227,"y is not 0"));
}
} catch(ErrorException& x) {
cerr << "Error "<<x.getError()<<" : "<<x.getMesssage()<<endl;
}
cout << "Last error ever generated, if any: " << ErrorException::getLastErrror()<<endl;
}
Neverthesess, I'd advise you to have a look at std::exception before reinventing the wheel.
This is an example of what I often do when I want to add some information to an exception:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Is there a nicer way to do it?
The standard exceptions can be constructed from a std::string:
#include <stdexcept>
char const * configfile = "hardcode.cfg";
std::string const anotherfile = get_file();
throw std::runtime_error(std::string("Failed: ") + configfile);
throw std::runtime_error("Error: " + anotherfile);
Note that the base class std::exception can not be constructed thus; you have to use one of the concrete, derived classes.
Here is my solution:
#include <stdexcept>
#include <sstream>
class Formatter
{
public:
Formatter() {}
~Formatter() {}
template <typename Type>
Formatter & operator << (const Type & value)
{
stream_ << value;
return *this;
}
std::string str() const { return stream_.str(); }
operator std::string () const { return stream_.str(); }
enum ConvertToString
{
to_str
};
std::string operator >> (ConvertToString) { return stream_.str(); }
private:
std::stringstream stream_;
Formatter(const Formatter &);
Formatter & operator = (Formatter &);
};
Example:
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData); // implicitly cast to std::string
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData >> Formatter::to_str); // explicitly cast to std::string
There are different exceptions such as runtime_error, range_error, overflow_error, logic_error, etc.. You need to pass the string into its constructor, and you can concatenate whatever you want to your message. That's just a string operation.
std::string errorMessage = std::string("Error: on file ")+fileName;
throw std::runtime_error(errorMessage);
You can also use boost::format like this:
throw std::runtime_error(boost::format("Error processing file %1") % fileName);
The following class might come quite handy:
struct Error : std::exception
{
char text[1000];
Error(char const* fmt, ...) __attribute__((format(printf,2,3))) {
va_list ap;
va_start(ap, fmt);
vsnprintf(text, sizeof text, fmt, ap);
va_end(ap);
}
char const* what() const throw() { return text; }
};
Usage example:
throw Error("Could not load config file '%s'", configfile.c_str());
Use string literal operator if C++14 (operator ""s)
using namespace std::string_literals;
throw std::exception("Could not load config file '"s + configfile + "'"s);
or define your own if in C++11. For instance
std::string operator ""_s(const char * str, std::size_t len) {
return std::string(str, str + len);
}
Your throw statement will then look like this
throw std::exception("Could not load config file '"_s + configfile + "'"_s);
which looks nice and clean.
Maybe this?
throw std::runtime_error(
(std::ostringstream()
<< "Could not load config file '"
<< configfile
<< "'"
).str()
);
It creates a temporary ostringstream, calls the << operators as necessary and then you wrap that in round brackets and call the .str() function on the evaluated result (which is an ostringstream) to pass a temporary std::string to the constructor of runtime_error.
Note: the ostringstream and the string are r-value temporaries and so go out of scope after this line ends. Your exception object's constructor MUST take the input string using either copy or (better) move semantics.
Additional: I don't necessarily consider this approach "best practice", but it does work and can be used at a pinch. One of the biggest issues is that this method requires heap allocations and so the operator << can throw. You probably don't want that happening; however, if your get into that state your probably have way more issues to worry about!
There are two points to answer in regards to what you want:
1.
The first point is that the nicer way is creating special types (classes) for custom exceptions and passing parameters as fields of the classes.
Something like the following:
class BaseFor_Exceptions : public std::exception {
protected:
BaseFor_Exceptions();
};
class Exception1 : public BaseFor_Exceptions {
public:
Exception1(uint32_t value1);
private:
uint32_t value1;
};
throw Exception1(0);
The second point is that you are performing memory allocations when preparing the exception object because of trying to pass a value of variable size (filename).
There is a possibility (when changing objects of the both std::string and std::stringstream ) of std::bad_alloc exception to be thrown in the process of it, so that you fail to prepare or throw (*) your exception – you will lose the info and the state.
In a well-designed program it is easy to avoid memory allocation when preparing or handling an exception. All that you need is just:
either guarantee the value is still life when handling the exception and pass some kind of link to the value as a part of the exception – either reference or some kind (most likely smart) of pointer,
or get the value when handling the exception using the exception type info or/and fixed-size values;
for example,
} catch (const ConfigurationLoadError & ex) {
std::cerr
<< “Some message 1 ”
<< serviceLocator1.SomeGetMethod1().Get_ConfigurationFileName();
} catch (const SomeException & ex) {
std::cerr
<< “Some message 2 ”
<< serviceLocator1.SomeGetMethod2().GetEventDetailsString(ex.Get_Value1());
}
Of course, you always have an option to accept buffer size limitations and use a pre-allocated buffer.
Also, please note that the type (classes) used for exceptions are not permitted to throw exceptions out of their copy constructors since, if the initial exception is attempted to be caught by value, a call of copy constructor is possible (in case is not elided by the compiler) and this additional exception will interrupt the initial exception handling before the initial exception is caught, which causes calling std::terminate.
Since C++11 compilers are permitted to eliminate the copying in some cases when catching, but both the elision is not always sensible and, if sensible, it is only permission but not obligation (see https://en.cppreference.com/w/cpp/language/copy_elision for details; before C++11 the standards of the language didn’t regulate the matter).
'*' Also, you should avoid exceptions (will call them the additional) to be thrown out of constructors and move constructors of your types (classes) used for exceptions (will call them initial) since the constructors and move constructors could be called when throwing objects of the types as initial exceptions, then throwing out an additional exception would prevent creation of an initial exception object, and the initial would just be lost. As well as an additional exception from a copy constructor, when throwing an initial one, would cause the same.
Ran into a similar issue, in that creating custom error messages for my custom exceptions make ugly code. This was my solution:
class MyRunTimeException: public std::runtime_error
{
public:
MyRunTimeException(const std::string &filename):std::runtime_error(GetMessage(filename)) {}
private:
static std::string GetMessage(const std::string &filename)
{
// Do your message formatting here.
// The benefit of returning std::string, is that the compiler will make sure the buffer is good for the length of the constructor call
// You can use a local std::ostringstream here, and return os.str()
// Without worrying that the memory is out of scope. It'll get copied
// You also can create multiple GetMessage functions that take all sorts of objects and add multiple constructors for your exception
}
}
This separates the logic for creating the messages. I had originally thought about overriding what(), but then you have to capture your message somewhere. std::runtime_error already has an internal buffer.
Whenever I need a custom message to be thrown in an exception, I construct a C-style string with snprintf() and pass it to the exception constructor.
if (problem_occurred) {
char buffer[200];
snprintf(buffer, 200, "Could not load config file %s", configfile);
string error_mesg(buffer);
throw std::runtime_error(error_mesg);
}
I'm not sure if the extra string string error_mesg(buffer) is necessary. I reason that the buffer is on stack memory, and if the exception catcher keeps running, then allowing the catcher to keep a reference to a stack-allocated C string is problematic. Instead, passing a string to the exception will invoke copy-by-value, and the buffer array will be deep-copied.
In case dynamic_cast<SomeType&> fails bad_cast exception is thrown. In my code there's a separate hierarchy of exceptions and bad_cast is not in that hierarchy so my code won't handle bad_cast. May I have some other exception thrown instead?
I mean I'd like to write a custom handler like this:
void OnBadCast()
{
throw MyException( "Bad cast" );
}
and somehow register it in C++ runtime
RegisterMyBadCastHandler( &OnBadCast );
so that this handler is invoked instead of bad_cast being thrown.
Is that possible?
I don't think you can change this behaviour.
What you could do, is use your own caster, however:
template<class T, class E> T myCast(E expr)
{
try
{
return dynamic_cast<T>(expr);
}
catch(std::bad_cast e)
{
// custom handler
}
};
Bad casts usually indicate a bug in the program (like eg. out of range, or out of memory), and thus should not be caught at all (or perhaps at the top-level). If you want to branch upon the success of dynamic_cast, then test for null in the pointer form:
if (T* p = dynamic_cast<T*>(some_ptr))
{
// Do something with p
}
If you want a special handler, the best you can do is thus the following:
template <typename T, typename U>
T& polymorphic_cast(U& x)
{
if (T* p = dynamic_cast<T*>(&x)) return *p;
my_handler();
}
where my_handler is supposed to kill the program (and perhaps log the error). But here, you may prefer using the plain dynamic_cast<T&> form, let std::bad_cast bubble up and be logged at the top level. This also plays better with debuggers, which can be set up to stop at the point where the cast fails.
Cases like you describe in your comments are rare enough to warrant special consideration, eg.:
if (auto p = dynamic_cast<foo*>(q)) { do_something(); }
else { throw bail_me_out_of_here(); }
may be used to indicate some upstream strategist that it should try another method.
You do not need to have exceptions in the same hierarchy to handle them. At least not in VC++. If you are just worried about handling different types of errors, do something like the below. If this answer does not suffice, the others are excellent considering the limitations you are working with, although take note of when bad_cast is thrown and when it is not. http://answers.yahoo.com/question/index?qid=20071106101012AAggZAk
#include <iostream>
#include <exception>
using namespace std;
class my_exception {
public:
explicit my_exception() {};
const char* msg() const { return "my_exception"; }
};
int main()
{
try {
// comment either line.
throw std::exception("std::exception");
throw my_exception();
}
catch (const std::exception& e )
{
cout << e.what() << endl;
}
catch (const my_exception& e)
{
cout << e.msg() << endl;
}
return 0;
}
The following code works just fine:
#include <exception>
using namespace std;
class FileException : public exception { // error occurs here
int _error;
// string _error; <-- this would cause the error
public:
FileException(int error);
// FileException(string error);
const char* what() const throw();
};
But as soon as I change the type of _error to string, the following compile error occurs:
Exception specification of overriding function is more lax than base version
The destructor of std::string is not no-throw, which causes the implicit destructor of FileException not no-throw either. But the destructor of std::exception is no-throw, thus there's a compiler error.
You could declare an explicit no-throw destructor:
virtual ~FileException() throw() {}
or just inherit from std::runtime_error instead of std::exception, which has a constructor that takes std::string input.
Simplify with:
// Derive from std::runtime_error rather than std::exception
// std::runtime_error (unlike std::exception) accepts a string as an argument that will
// be used as the error message.
//
// Note: Some versions of MSVC have a non standard std::exception that accepts a string
// Do not rely on this.
class FileException : public std::runtime_error
{
public:
// Pass error msg by const reference.
FileException(std::string const& error)
// Pass the error to the standard exception
: std::runtime_error(error)
{}
// what() is defined in std::runtime_error to do what is correct
};
I approve of the above method,
but g++ seems to complain if
the default constructor is not present.
The following addition makes things work:
using namespace std;
class MyException : public runtime_error {
public:
/* add the following line: */
MyException() : runtime_error("MyException") { } // default constructor
MyException( string const& error ) : runtime_error(error) { } // ctor w/string
};
additionally, an exception list is easily created:
MyException FileNotFound ( "File Not Found" );
MyException ReadOnly ( "ReadOnly" );
MyException Unkown ( "Unknown" );
...
throw FileNotFound;
...
when catching these exceptions, if you don't need specificity catch them generically:
catch( runtime_error re) { cout << "Runtime Error: " << re.what() << endl; ... }
Since all MyExceptions decend from runtime_error this catches them all and
you won't miss any other runtime errors from the system either.
catch( exception e) { cout << "exception: " << e.what() << endl; ... }
catches them all.
In C++, you can also throw and catch any types (int, booleans,pointers, etc.) Its sometimes simpler
to just throw/catch a string or an int within a function block.
Multiple classes should only throw and catch code library standard exceptions and their subclasses, (and all in the same manner), however, mostly for consistency and maintenance, but also because c++ compilers know how to optimize the exception mechanisms and linkages for them, and can generate intelligent warnings and errors about them, easing debugging.
"Error: "0x137F" is for IBM guys, not "the third guy on the project this year" ...