【问题标题】:Deriving streambuf or basic_ostringstream?派生streambuf 或basic_ostringstream?
【发布时间】:2010-03-17 07:42:10
【问题描述】:

我想派生一个字符串流,这样我就可以使用运算符

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

这应该做一个

throw "some text more text 42"

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

【问题讨论】:

    标签: c++ ostream ostringstream streambuf


    【解决方案1】:

    您可能可以通过以下方式使其更容易:

    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&amp; 捕获。

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

    【讨论】:

    • 我不会真的抛出 const char*s。这只是一个概念。
    • 你不应该在析构函数中抛出异常 (parashift.com/c++-faq-lite/exceptions.html#faq-17.3)。
    • @Helltone:这是一个例外。了解您不应该一般(此处的关键字)抛出的原因:在堆栈展开期间,如果两个异常变为活动状态,则应用程序将终止。这显然不是这里的情况,因为它打算立即抛出。 (公平地说,流 可能 失败并抛出,但是,嗯。) 编辑:好吧,无论如何都要修复它,所以你去。 :)
    • @Helltone:默认情况下流的异常是关闭的,流异常是error_builder 的生命周期内可能抛出的少数事情之一。否则,唯一可能被抛出的就是std::bad_alloc,如果发生这种情况,那么std::terminate 可能是最好的。
    • 第一次执行
    【解决方案2】:

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

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

    使用中:

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

    异常类型来自我自己的库,但我想你明白了。这比派生自己的流类要简单得多,并且避免了 op

    【讨论】:

    • 有时,宏是最好的解决方案。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-01-29
        • 1970-01-01
        • 2021-02-08
        • 1970-01-01
        • 1970-01-01
        • 2013-07-29
        • 2020-10-14
        相关资源
        最近更新 更多