【问题标题】:Use of stringstream within ostream function在 ostream 函数中使用 stringstream
【发布时间】:2012-10-15 21:16:51
【问题描述】:

我正在考虑为某些数学类(矩阵、向量等)提供ostream 运算符。一位朋友注意到,std::complexostream 运算符的 gcc 标准库实现包括内部使用在将输出传递给实际的ostream之前格式化输出的字符串流:

///  Insertion operator for complex values.
template<typename _Tp, typename _CharT, class _Traits>
  basic_ostream<_CharT, _Traits>&
  operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x)
{
  basic_ostringstream<_CharT, _Traits> __s;
  __s.flags(__os.flags());
  __s.imbue(__os.getloc());
  __s.precision(__os.precision());
  __s << '(' << __x.real() << ',' << __x.imag() << ')';
  return __os << __s.str();
}

这种模式在 boost 中也可见。我们正在尝试确定这是否是值得遵循的模式。有人担心它涉及为字符串流包含一个额外的标头,并且在字符串流中需要额外的堆分配,这可能是可以避免的。

最合理的建议是,如果客户端需要该功能,那么他们可以创建字符串流并自己进行预传递。

谁能帮我理解为什么这会被认为是好的做法以及我是否应该采用它?

【问题讨论】:

    标签: c++ ostream


    【解决方案1】:

    考虑如果您在 ostream 上设置输出宽度,然后向其写入 std::complex 会发生什么 - 您不希望宽度仅影响第一个输出操作(即 '(' 字符)

    std::complex i(0, 1);
    std::cout << std::setw(10) << std::left << i;
    

    这应该打印"(0,1)     " 而不是"(         0,1)"

    通过将整个输出形成为单个字符串,然后将其写出,输出会尊重流上设置的字段宽度和其他格式标志。

    【讨论】:

      【解决方案2】:

      另一个响应中引用的线程原因不会真正解决:字符串仍然可以在流缓冲区级别拆分,因为这些操作在从多个线程调用时不是原子的。

      但是,有两个相关的考虑因素:

      1. 对于某些输出,您希望临时更改格式标志设置。例如,您想确保某个字符串使用十六进制表示法出现,而对于其他十进制表示法,您希望将流恢复到其原始状态。
      2. 更重要的是,输出的width() 的含义是整个格式化字符串至少应该占据的字符数。如果您在另一个输出运算符内部使用输出运算符,您将使第一个元素占据宽度,而不是由多个组件组成的整个字符串。例如,对于复数,实数元素将占据width(),而不是实数元素、逗号和虚数元素的组合。

      【讨论】:

        【解决方案3】:

        此模式的一个主要目的是避免保留原始流的操纵器/标志并在返回之前重置它们。 Boost.IoStateSavers 不需要这样做,所以我会说使用上述库会是更好的做法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-01-14
          • 1970-01-01
          • 1970-01-01
          • 2017-04-08
          • 1970-01-01
          • 2021-02-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多