Dagg Nabbit
Dagg Nabbit

Reputation: 76736

Runtime exception messages without extending std::exception

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

Answers (2)

PiotrNycz
PiotrNycz

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

Mike Seymour
Mike Seymour

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

Related Questions