Restore the state of std::cout after manipulating it

C++Iostream

C++ Problem Overview


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 cout to its original one after returning from the function? (Somewhat like std::boolalpha and std::noboolalpha..) ?

Thanks.

C++ Solutions


Solution 1 - C++

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

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 answer on how to use this with RAII.

Solution 2 - C++

Note that the answers presented here won't restore the full state of std::cout. For example, std::setfill will "stick" even after calling .flags(). A better solution is to use .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

Solution 3 - C++

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

Example based on your code snippet:

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

Solution 4 - C++

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.

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.

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

Solution 5 - C++

You can create another wrapper around the stdout buffer:

#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 ios object (but not the buffer) including some stuff that you're paying for but unlikely to use such as the locale.

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

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

Solution 6 - C++

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

Solution 7 - C++

C++20 std::format will be a superior alternative to save restore in most cases

Once you can use it, you will e.g. be able to write hexadecimals simply as:

#include <format>
#include <string>

int main() {
    std::cout << std::format("{x} {#x} {}\n", 16, 17, 18);
}

Expected output:

10 0x11 18

This will therefore completely overcome the madness of modifying std::cout state.

More information at: https://stackoverflow.com/questions/479373/c-cout-hex-values/64048139#64048139

Solution 8 - C++

I would like to generalize the answer from qbert220 somewhat:

#include <ios>

class IoStreamFlagsRestorer
{
public:
    IoStreamFlagsRestorer(std::ios_base & ioStream)
        : ioStream_(ioStream)
        , flags_(ioStream_.flags())
    {
    }

    ~IoStreamFlagsRestorer()
    {
        ioStream_.flags(flags_);
    }

private:
    std::ios_base & ioStream_;
    std::ios_base::fmtflags const flags_;
};

This should work for input streams and others as well.

PS: I would have liked to make this simply a comment to above answer, stackoverflow however does not allow me to do so because of missing reputation. Thus make me clutter the answers here instead of a simple comment...

Solution 9 - C++

Instead of injecting format into cout, the << way, adopting setf and unsetf could be a cleaner solution.

void printHex(std::ostream& x){
  x.setf(std::ios::hex, std::ios::basefield);
  x << 123;
  x.unsetf(std::ios::basefield);
}

the ios_base namespace works fine too

void printHex(std::ostream& x){
  x.setf(std::ios_base::hex, std::ios_base::basefield);
  x << 123;
  x.unsetf(std::ios_base::basefield);
}

Reference: http://www.cplusplus.com/reference/ios/ios_base/setf/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionUltraInstinctView Question on Stackoverflow
Solution 1 - C++Stefan KendallView Answer on Stackoverflow
Solution 2 - C++rr-View Answer on Stackoverflow
Solution 3 - C++Chris Jester-YoungView Answer on Stackoverflow
Solution 4 - C++qbert220View Answer on Stackoverflow
Solution 5 - C++n.caillouView Answer on Stackoverflow
Solution 6 - C++whacko__CrackoView Answer on Stackoverflow
Solution 7 - C++Ciro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 8 - C++J. WildeView Answer on Stackoverflow
Solution 9 - C++aGueguView Answer on Stackoverflow