操作后恢复std :: cout的状态

假设我有这样的代码:

void printHex(std::ostream& x){ x<<std::hex<<123; } .. int main(){ std::cout<<100; // prints 100 base 10 printHex(std::cout); //prints 123 in hex std::cout<<73; //problem! prints 73 in hex.. } 

我的问题是,如果有什么办法从函数返回后将cout的状态恢复到原来的状态? (有点像std :: boolalpha和std :: noboolalpha ..)?

谢谢。

谷歌search给了我这个:

  ios::fmtflags f( cout.flags() ); //Your code here... cout.flags( f ); 

你可能想把它放在你的函数的头部和尾部。

升压IOstream状态节电器正是您所需要的。 🙂

基于你的代码片段的例子:

 void printHex(std::ostream& x) { boost::io::ios_flags_saver ifs(x); x << std::hex << 123; } 

请注意,这里给出的答案不会恢复std::cout的完整状态。 例如,即使在调用.flags()之后, std::setfill也会“粘住”。 更好的解决scheme是使用.copyfmt

 std::ios oldState(nullptr); oldState.copyfmt(std::cout); std::cout << std::hex << std::setw(8) << std::setfill('0') << 0xDECEA5ED << std::endl; std::cout.copyfmt(oldState); std::cout << std::setw(15) << std::left << "case closed" << std::endl; 

将打印:

 case closed 

而不是:

 case closed0000 

我使用这个答案中的示例代码创build了一个RAII类。 如果你有一个函数在iostream上设置了多个返回path,这个技巧的好处就来了。 无论使用哪条返回path,析构函数将始终被调用,并且标志将始终得到重置。 当函数返回时,没有机会忘记恢复标志。

 class IosFlagSaver { public: explicit IosFlagSaver(std::ostream& _ios): ios(_ios), f(_ios.flags()) { } ~IosFlagSaver() { ios.flags(f); } IosFlagSaver(const IosFlagSaver &rhs) = delete; IosFlagSaver& operator= (const IosFlagSaver& rhs) = delete; private: std::ostream& ios; std::ios::fmtflags f; }; 

然后,只要想要保存当前的标志状态,就可以通过创buildIosFlagSaver的本地实例来使用它。 当这个实例超出范围时,标志状态将被恢复。

 void f(int i) { IosFlagSaver iosfs(std::cout); std::cout << i << " " << std::hex << i << " "; if (i < 100) { std::cout << std::endl; return; } std::cout << std::oct << i << std::endl; } 

通过一些修改使输出更易读:

 void printHex(std::ostream& x) { ios::fmtflags f(x.flags()); x << std::hex << 123 << "\n"; x.flags(f); } int main() { std::cout << 100 << "\n"; // prints 100 base 10 printHex(std::cout); // prints 123 in hex std::cout << 73 << "\n"; // problem! prints 73 in hex.. } 

您可以在stdout缓冲区周围创build另一个包装:

 #include <iostream> #include <iomanip> int main() { int x = 76; std::ostream hexcout (std::cout.rdbuf()); hexcout << std::hex; std::cout << x << "\n"; // still "76" hexcout << x << "\n"; // "4c" } 

在一个函数中:

 void print(std::ostream& os) { std::ostream copy (os.rdbuf()); copy << std::hex; copy << 123; } 

当然,如果性能是一个问题,这是一个更昂贵的,因为它是复制整个ios对象(而不是缓冲区),包括一些你付出的东西,但不太可能使用,如区域设置。

否则,我觉得如果你打算使用.flags() ,最好保持一致并使用.setf() ,而不要使用<< syntax(纯粹的样式问题)。

 void print(std::ostream& os) { std::ios::fmtflags os_flags (os.flags()); std::size_t os_width (os.width()); os.setf(std::ios::hex); os.width(4); os << 123; os.flags(os_flags); os.width(os_width); } 

正如其他人所说的,为了方便起见,你可以把上面的(和.fill() .precision().fill() ,但通常不是通常不会被修改和更重的语言环境和词语相关的东西)使其exception安全; 构造函数应该接受std::ios&