如何自动将流模式设置回默认值

时间:2018-02-08 02:51:13

标签: c++ iostream raii

C ++ steam对象具有状态。如果一个人写一段代码,如

using namespace std; 
cout << hex << setw(8) << setfill('0') << x << endl;

忘记设置流状态。这将导致其他一些不相关的代码出现问题。做起来很繁琐&#34;设置&#34;并且&#34;退回&#34;配对。除此之外,在我看来,它也反对RAII背后的惯例。

我的问题是:是否有可能只用一层薄薄的包裹来使这些状态操作成为类RAII。也就是说,在分号表达式结束后,流状态会自动设置回默认值。

更新:按照@ 0x499602D2提供的链接,一个解决方法可能类似

#include <boost/io/ios_state.hpp>
#include <ios>
#include <iostream>
#include <ostream>
#define AUTO_COUT(x) {\
    boost::io::ios_all_saver  ias( cout );\
    x;\
    }while(0)

然后可以使用像

这样的宏
AUTO_COUT(cout << hex << setw(8) << setfill('0') << x << endl);
顺便说一下,如果在多线程程序中出现有趣的事情,可以将一个锁定字段添加到boost :: io :: ios_state的保护类中,这可能是一个好主意。或者他们已经这样做了?

2 个答案:

答案 0 :(得分:3)

我将建议另一种方法。操纵符适用于std::[i|o]stream实例,但它们对由std::[i|o]streambuf管理的std::[i|o]stream无效。

因此,您可以创建自己的std::[i|o]stream,它将具有自己的格式化状态,但写入相同的缓冲区std::cout会使用:

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::hex << 32 << "\n";
    std::ostream os(std::cout.rdbuf());
    os << 32 << "\n" << std::hex;
    std::cout << std::dec;
    os << 32 << "\n";
    std::cout << 32 << "\n";
}

输出:

20
32
20
32

Live on Coliru

这仅使用标准库中的功能,并且由于未触及原始流,因此应用操纵器非常简单(因为每个线程在不同的流上运行)。现在,实际写入和读取的线程安全性取决于托管流缓冲区的线程安全性。

答案 1 :(得分:2)

我曾经写过一个实用课程供我个人使用。 (我不知道它是否像升级代码一样完美,但它对我有用 - 所以,我敢于分享。)

#include <iostream>
#include <iomanip>

/** provides a helper class to work with streams.
 *
 * It stores current format states of a stream in constructor and
 * recovers these settings in destructor.
 *
 * Example:
 * <pre>
 * { // backup states of std::cout
 *   IOSFmtBackup stateCOut(std::cout);
 *   // do some formatted output
 *   std::cout
 *     << "dec: " << std::dec << 123 << std::endl
 *     << "hex: " << std::hex << std::setw(8) << std::setfill('0')
 *     << 0xdeadbeef << std::endl;
 * } // destruction of stateCOut recovers former states of std::cout
 * </pre>
 */
class IOSFmtBackup {

  // variables:
  private:
    /// the concerning stream
    std::ios &_stream;
    /// the backup of formatter states
    std::ios _fmt;

  // methods:
  public:
    /// @name Construction & Destruction
    //@{

    /** constructor.
     *
     * @param stream the stream for backup
     */
    explicit IOSFmtBackup(std::ios &stream):
      _stream(stream), _fmt(0)
    {
      _fmt.copyfmt(_stream);
    }

    /// destructor.
    ~IOSFmtBackup() { _stream.copyfmt(_fmt); }

    // disabled:
    IOSFmtBackup(const IOSFmtBackup&) = delete;
    IOSFmtBackup& operator=(const IOSFmtBackup&) = delete;
    //@}
};

int main()
{
  { // backup states of std::cout
    IOSFmtBackup stateCOut(std::cout);
    // do some formatted output
    std::cout
      << "dec: " << std::dec << 123 << std::endl
      << "hex: " << std::hex << std::setw(8) << std::setfill('0')
      << 0xdeadbeef << std::endl
      << "123 in current: " << 123 << std::endl;
  } // destruction of stateCOut recovers former states of std::cout
  // check whether formatting is recovered
  std::cout << "123 after recovered: " << 123 << std::endl;
  return 0;
}

ideone (life demo)上进行了编译和测试。

输出:

dec: 123
hex: deadbeef
123 in current: 7b
123 after recovered: 123