Question

I want to derive a stringstream so that I can use the operator<< to construct a message which will then be thrown. The API would look like:

error("some text") << " more text " << 42 << std::endl;

This should do a

throw "some text more text 42"

So what I did is make an errorbuf (inheriting from streambuf) which overloads the 'overflow' method and then create an ostream(&errorbuf). I wonder if I shouldn't instead inherit from basic_ostringstream or something...

Was it helpful?

Solution

I'll trot out my favourite macro again here:

#define ATHROW( msg )                                               \
{                                                                   \
    std::ostringstream os;                                          \
    os << msg;                                                      \
    throw ALib::Exception( os.str(), __LINE__, __FILE__ );          \
}                                                                   \

In use:

ATHROW( "Invalid value: " << x << " should be " << 42 );

the exception type is from my own library, but I think you get the idea. This is much simpler than deriving your own stream class, and avoids lots of nasty complications with op<<().

OTHER TIPS

You could probably make it easier by doing something like:

class error_builder
{
public:
    error_builder(const std::string& pMsg = "")
    {
        mMsg << pMsg;
    }

    ~error_builder(void)
    {
        throw std::runtime_error(mMsg.str());
    }

    template <typename T>
    error_builder& operator<<(const T& pX)
    {
        mMsg << pX;

        return *this;
    }

private:
    std::stringstream mMsg;    
};


error_builder("some text") << " more text " << 42 << std::endl;

Note that you shouldn't throw strings like you are, hence I used std::runtime_error. All exceptions should derive from std::exception, which runtime_error does, that way all meaningful exceptions can be caught with const std::exception&.

This works because the temporary lives until the end of the full expression.

Some operators are missing from GMan's solution.

class error {
   public:
   explicit error(const std::string& m = "") :
          msg(m, std::ios_base::out | std::ios_base::ate)
   {}

   ~error() {
      if(!std::uncaught_exception()) {
         throw std::runtime_error(msg.str());
      }
   }

   template<typename T>
   error& operator<<(const T& t) {
      msg << t;
      return *this;
   }

   error& operator<<(std::ostream& (*t)(std::ostream&)) {
      msg << t;
      return *this;
   }
   error& operator<<(std::ios& (*t)(std::ios&)) {
      msg << t;
      return *this;
   }
   error& operator<<(std::ios_base& (*t)(std::ios_base&)) {
      msg << t;
      return *this;
   }
   private:
   std::ostringstream msg;
};

I usually just create my own exception classes. You only have to override what() and can provide as many constructors as you like. To build up the error message, just use vasprintf (if available) or std::ostringstream like above.

Here's an example:

class CustomException : public std::exception {
private:
    const std::string message;
public:
    CustomException(const std::string &format, ...) {
        va_list args;
        va_start(args, format);
        char *formatted = 0;
        int len = vasprintf(&formatted, format.c_str(), args);
        if (len != -1) {
            message = std::string(formatted);
            free(formatted);
        } else {
            message = format;
        }
        va_end(args);
    }
    const char *what() const {
        return message.c_str();
    }
};

If you don't have vasprintf, you can also use vsnprintf with a buffer on the stack...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top