2

我想派生一个字符串流,以便我可以使用 operator<< 构造一条消息,然后将其抛出。API 看起来像:

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

这应该做一个

throw "some text more text 42"

所以我所做的是创建一个errorbuf(继承自streambuf),它重载'overflow'方法,然后创建一个ostream(&errorbuf)。我想知道我是否不应该从 basic_ostringstream 或其他东西继承...

4

4 回答 4

3

您可以通过执行以下操作使其更容易:

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;

请注意,您不应该像现在这样抛出字符串,因此我使用了std::runtime_error. 所有异常都应该从 const 派生std::exceptionruntime_error这样所有有意义的异常都可以用 const 捕获std::exception&

这是有效的,因为临时的存在直到完整的表达结束。

于 2010-03-17T07:49:34.197 回答
2

我将在这里再次展示我最喜欢的宏:

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

正在使用:

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

异常类型来自我自己的库,但我想你明白了。这比派生自己的流类要简单得多,并且避免了 op<<() 带来的许多令人讨厌的并发症。

于 2010-03-17T10:05:00.170 回答
2

GMan 的解决方案中缺少一些运算符。

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;
};
于 2010-03-17T12:41:14.497 回答
0

我通常只是创建自己的异常类。您只需要覆盖what()并且可以提供任意数量的构造函数。要构建错误消息,只需使用 vasprintf(如果可用)或 std::ostringstream 就像上面一样。

这是一个例子:

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();
    }
};

如果你没有 vasprintf,你也可以在堆栈上使用带有缓冲区的 vsnprintf...

于 2011-08-08T13:52:14.540 回答