Reputation: 76736
I have some code like this:
class ParseError: public exception {
protected:
mutable string msg;
int position;
public:
explicit ParseError(const string& message, const int index) {
msg = message;
position = index;
}
virtual ~ParseError() throw () {
}
const char * what() const throw () {
stringstream ss(msg);
ss << "Parse error at position " << position << ": " << msg;
msg = ss.str();
return msg.c_str();
}
};
When I throw it, I see something like this when running unit tests under valgrind:
foo.h:102: Unexpected exception with message: 'Parse error at position 9: Found unexpected character(s): blah'
This is what I want, but I was curious what the exception
base class is doing behind the scenes. If I don't extend exception
but leave the rest of the class as-is, I get this:
foo.h:102: Unexpected exception with message: 'Unknown exception'
What would I need to add to my class in order to be able to not extend exception
and still have the message show up?
By the way, I realize that I should probably be extending runtime_error
rather than exception
. In this case, I'm curious what makes exception
tick behind the scenes, I'm not necessarily looking for advice on best practices.
Upvotes: 2
Views: 590
Reputation: 24347
Two problems here:
In this function you putting msg
to itself:
const char * what() const throw () {
stringstream ss(msg);
** ^^^
ss << "Parse error at position " << position << ": " << msg;
** ^^^
But this is not very important since your second problem is that you should move creating message from what()
to constructor. what()
should only returns it.
class ParseError: public exception {
protected:
string msg;
public:
explicit ParseError(const string& message, const int index) {
ostringstream ss;
ss << "Parse error at position " << position << ": " << message;
msg << ss.str();
}
const char * what() const throw () {
return msg.c_str();
}
};
Upvotes: 1
Reputation: 254431
There is no guarantee that you'll get a useful error message if you don't handle an exception; the only guarantee is that the program will be terminated by calling std::terminate
.
It seems that your implementation is able to identify that the unhandled exception was derived from std::exception
, and use that knowledge to call its override of what()
to generate an error message. It would know nothing about non-standard exception types, and it shouldn't randomly call functions just because they happen to have the same name as a function in a completely unrelated class.
If you want to print something useful when an arbitrary type is thrown, you'll need a handler to catch that type and do the right thing with it. But I would definitely advise you to only throw types derived from std::exception
unless you've got a very good reason to throw something else.
Upvotes: 2