【问题标题】:How to automatically set stream mode back to default [duplicate]如何自动将流模式设置回默认值[重复]
【发布时间】:2018-07-18 12:09:11
【问题描述】:

C++ 蒸汽对象有状态。如果有人写一段代码,比如

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

忘记设置流状态。这会导致其他一些不相关的代码出现问题。进行“set”和“set back”配对匹配很乏味。除此之外,在我看来这也违反了 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 的保护类中添加一个锁定字段可能是个好主意,以防多线程程序中发生有趣的事情。还是他们已经这样做了?

【问题讨论】:

  • @0x499602D2 boost::io::ios_state 是否保护流状态免受状态的多线程操作?
  • 不,它没有。
  • 为了使您的AUTO_COUT() 线程安全,也可以添加std::lockguard&lt;std::mutex&gt;。有趣,够了。我回答中的代码曾经受到这些监护人的启发。 :-) (我是在 gtkmm 中第一次看到的。)

标签: c++ iostream raii


【解决方案1】:

我将建议一种替代方法。操纵器适用于std::[i|o]stream 实例,但它们对由std::[i|o]stream 管理的std::[i|o]streambuf 不执行任何操作。

因此,您可以创建自己的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

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

【讨论】:

  • 这很好,特别是因为它考虑了线程安全的(每条评论添加)要求(?)。不过,现在,实际写入和读取的线程安全性取决于托管流缓冲区的线程安全性。 这让我感到好奇。我相信,可以肯定的是,您必须提供一个自己的、线程安全的流缓冲区。然后,我想到了别的东西:线程安全的流缓冲区可能会授予线程安全性(这对于健壮的应用程序来说肯定不错),但并不是说并发线程的输出不会被意外混合。对于后者,输出操作(整体)必须受到保护(例如,通过互斥锁)。
  • @Scheff 不确定 streambuf 类的保证,但如果它们实际上是线程安全的,那么,是的,可以删除此注释。 Wrt I/O 混合,std::syncbuf 为 C++20 提议的类可能会有所帮助en.cppreference.com/w/cpp/io/basic_syncbuf
  • @milleniumbug 如果设置了sync_with_stdio(这是默认设置),该标准保证标准流是线程安全的。但是,它不能保证它们的流缓冲区在从其他流中使用时是线程安全的。而且,正如 Scheff 所说,防止交错无论如何都需要外部同步,所以使用它似乎是个好主意。
【解决方案2】:

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

#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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-03
    • 2014-07-11
    • 2017-07-24
    • 2015-01-06
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多