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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2273330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:49:17  来源:igfitidea点击:

Restore the state of std::cout after manipulating it

c++iostream

提问by UltraInstinct

Suppose I have a code like this:

假设我有这样的代码:

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..
}

My question is if there is any way to 'restore' the state of coutto its original one after returning from the function? (Somewhat like std::boolalphaand std::noboolalpha..) ?

我的问题是,cout从函数返回后,是否有任何方法可以将状态“恢复”到原来的状态?(有点喜欢std::boolalphastd::noboolalpha..)?

Thanks.

谢谢。

采纳答案by Stefan Kendall

you need to #include <iostream>or #include <ios>then when required:

您需要#include <iostream>#include <ios>在需要时:

std::ios_base::fmtflags f( cout.flags() );

//Your code here...

cout.flags( f );

You can put these at the beginning and end of your function, or check out this answeron how to use this with RAII.

您可以将它们放在函数的开头和结尾,或者查看有关如何将其与RAII一起使用的答案

回答by Chris Jester-Young

The Boost IO Stream State Saverseems exactly what you need. :-)

升压IO流状态节电器似乎正是你需要的。:-)

Example based on your code snippet:

基于您的代码片段的示例:

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

回答by rr-

Note that the answers presented here won't restore the full state of std::cout. For example, std::setfillwill "stick" even after calling .flags(). A better solution is to use .copyfmt:

请注意,此处提供的答案不会恢复std::cout. 例如,std::setfill即使在调用.flags(). 更好的解决方案是使用.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;

Will print:

将打印:

case closed

rather than:

而不是:

case closed0000

回答by qbert220

I've created an RAII class using the example code from this answer. The big advantage to this technique comes if you have multiple return paths from a function that sets flags on an iostream. Whichever return path is used, the destructor will always be called and the flags will always get reset. There is no chance of forgetting to restore the flags when the function returns.

我使用此答案中的示例代码创建了一个 RAII 类。如果在 iostream 上设置标志的函数有多个返回路径,则此技术的巨大优势就来了。无论使用哪个返回路径,总是会调用析构函数并且总是会重置标志。当函数返回时,不会忘记恢复标志。

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;
};

You would then use it by creating a local instance of IosFlagSaver whenever you wanted to save the current flag state. When this instance goes out of scope, the flag state will be restored.

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

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;
}

回答by n.caillou

You can create another wrapper around the stdout buffer:

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

#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"
}

In a function:

在一个函数中:

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

Of course if performance is an issue this is a bit more expensive because it's copying the entire iosobject (but not the buffer) including some stuff that you're paying for but unlikely to use such as the locale.

当然,如果性能是一个问题,这会更昂贵一些,因为它复制整个ios对象(但不是缓冲区),包括一些您付费但不太可能使用的内容,例如语言环境。

Otherwise I feel like if you're going to use .flags()it's better to be consistent and use .setf()as well rather than the <<syntax (pure question of style).

否则我觉得如果你要使用.flags()它最好保持一致并使用.setf()而不是<<语法(纯粹的风格问题)。

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

As others have said you can put the above (and .precision()and .fill(), but typically not the locale and words-related stuff that is usually not going to be modified and is heavier) in a class for convenience and to make it exception-safe; the constructor should accept std::ios&.

正如其他人所说,为了方便并使其异常安全,您可以将上述(和.precision().fill(),但通常不是通常不会修改且更重的语言环境和与单词相关的内容)放在一个类中;构造函数应该接受std::ios&.

回答by whacko__Cracko

With a little bit of modification to make the output more readable :

稍加修改,使输出更具可读性:

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..
}