派生streambuf还是basic_ostringstream?

发布于 2024-08-25 14:52:15 字数 368 浏览 11 评论 0原文

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

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

这应该执行 a

throw "some text more text 42"

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

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...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

娇女薄笑 2024-09-01 14:52:15

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

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。所有异常都应从 std::exception 派生,runtime_error 就是如此,这样所有有意义的异常都可以用 const std::exception& 捕获。

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

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.

绳情 2024-09-01 14:52:15

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

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;
};
简单气质女生网名 2024-09-01 14:52:15

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

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

使用中:

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

异常类型来自我自己的库,但我认为您已经明白了。这比派生您自己的流类要简单得多,并且避免了 op<<() 带来的许多令人讨厌的复杂情况。

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<<().

两相知 2024-09-01 14:52:15

我通常只是创建自己的异常类。您只需重写 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 和堆栈上的缓冲区......

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...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文