操作后恢复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&
。