142

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.

leiyc
  • 903
  • 11
  • 23
UltraInstinct
  • 43,308
  • 12
  • 81
  • 104
  • I believe hex only lasts for the next shift out operation. The change is only persistent if you change the format flags manually instead of using manipulators. – Billy ONeal Feb 16 '10 at 15:39
  • 5
    @BillyONeal: No, using manipulators has the same effect as changing the format flags manually. :-P – C. K. Young Feb 16 '10 at 15:55
  • 3
    If you are here due to a Covertiy finding ***Not restoring ostream format (STREAM_FORMAT_STATE)***, then see [Coverity finding: Not restoring ostream format (STREAM_FORMAT_STATE)](http://stackoverflow.com/q/34503914). – jww Jan 25 '16 at 21:11
  • I did something similar - see my question on Code Review: [*Use a standard stream, and restore its settings afterwards*](//codereview.stackexchange.com/q/189753). – Toby Speight Aug 29 '18 at 14:50
  • 2
    This question is a perfect example of why iostream is not better than stdio. Just found two nasty bugs because of not-/semi-/fully-/what-not persistent iomanip. – fuujuhi Dec 16 '19 at 09:02
  • For what it worth. Just found that std::setw affects only the next shift operation when compiled using g++ 4.9..0 with -std=c++11 – uuu777 Aug 02 '22 at 15:50

9 Answers9

127

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.

Dev Null
  • 4,731
  • 1
  • 30
  • 46
Stefan Kendall
  • 66,414
  • 68
  • 253
  • 406
82

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
rr-
  • 14,303
  • 6
  • 45
  • 67
  • Although my original question has been answered a few years back, this answer is a great addition. :-) – UltraInstinct Jun 22 '15 at 07:49
  • 8
    @UltraInstinct It appears to be a *better* solution, in which case, you can and probably should make it the accepted answer instead. – underscore_d Sep 29 '18 at 23:30
  • This for some reasons throws exception if exceptions are enabled for the stream. http://coliru.stacked-crooked.com/a/2a4ce6f5d3d8925b – anton_rh Dec 29 '18 at 13:10
  • 1
    It seems that `std::ios` is always in **bad** state because it has `NULL` rdbuf. So setting a state with exceptions enabled causes exception throwing because of bad state. Solutions: 1) Use some class (for example `std::stringstream`) with `rdbuf` set instead of `std::ios`. 2) Save exceptions state separately to local variable and disable them before `state.copyfmt`, then restore exception from the variable (and do this again after restoring state from `oldState` which has exceptions disabled). 3) Set `rdbuf` to `std::ios` like this: `struct : std::streambuf {} sbuf; std::ios oldState(&sbuf);` – anton_rh Jan 09 '19 at 10:35
63

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;
}
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • 1
    Note that there's no magic here, that `ios_flags_saver` basically just saves and sets the flags like in @StefanKendall's answer. – einpoklum Feb 28 '16 at 13:10
  • 17
    @einpoklum But it is exception-safe, unlike the other answer. ;-) – C. K. Young Feb 28 '16 at 14:46
  • 2
    There's more to the stream state besides the flags. – jww Mar 18 '17 at 11:58
  • 4
    @jww The IO Stream State Saver library has multiple classes, for saving different parts of the stream state, of which `ios_flags_saver` is just one. – C. K. Young Mar 19 '17 at 04:58
  • 1
    Why for every small problem one should link against boost library...give me a break :D – Dumbo Oct 01 '17 at 10:33
  • 3
    If you think it's worth reimplementing and maintaining every little thing by yourself, instead of using a reviewed, well tested library ... – jupp0r Feb 05 '18 at 21:29
  • The link is now broken, here's the new address: https://www.boost.org/doc/libs/release/libs/io/doc/html/io.html – Max Barraclough Nov 16 '20 at 19:28
24

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;
}
qbert220
  • 11,220
  • 4
  • 31
  • 31
14

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

n.caillou
  • 1,263
  • 11
  • 15
  • Good point[+], but it of course remembers to using [`std::stringstream`](https://en.cppreference.com/w/cpp/io/basic_stringstream) for the formatting part as [Mark Sherred pointed out](https://stackoverflow.com/questions/2273330/restore-the-state-of-stdcout-after-manipulating-it/43771309#comment84146603_2273352). – Wolf Sep 17 '19 at 09:45
  • @Wolf I'm not sure I get your point. An `std::stringstream` _is_ an `std:ostream`, except using one introduces an extra intermediate buffer. – n.caillou Sep 17 '19 at 16:51
  • Of course both are valid approaches to formatting output, both introduce a stream object, the one you describe is new to me. I've to think about pros and cons now. However, an inspiring question with enlightening answers ... (I mean the stream copy variant) – Wolf Sep 18 '19 at 07:48
  • 2
    You can't copy a stream, because copying buffers often doesn't make sense (e.g. stdout). However, you can have several stream objects for the same buffer, which is what this answer proposes to do. Whereas an `std:stringstream` will create its own independent `std:stringbuf` (an `std::streambuf` derivate), which then needs to be poured into `std::cout.rdbuf()` – n.caillou Sep 20 '19 at 17:02
  • @n.caillou "The" `std::ostream` instance is typically provided by the client (or is global, e.g. `std::cout`), and the client/global `ostream` state is what needs to be maintained/restored when returning. The local/auto `std::stringstream` lets you isolate the state tweaks to a local `std::ostream` instead of manipulating the state of the client's `std::ostream` (or `cout`). – franji1 Sep 08 '21 at 13:43
  • 1
    @franji1 again, you can do that without creating a stringbuf. you have not understood the answer; streams and buffers are separate things – n.caillou Mar 18 '22 at 20:51
  • Still a fantastic answer to learn from (and I've learned the lesson about “copying” streams). Those who are interested in the meaning of *rd* may read [*What does STL “rdbuf” method name stand for?*](https://stackoverflow.com/q/32770387/2932052) – Wolf Jun 09 '23 at 13:48
10

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.

The existing fmt library implements it for before it gets official support: https://github.com/fmtlib/fmt Install on Ubuntu 22.04:

sudo apt install libfmt-dev

Modify source to replace:

  • <format> with <fmt/core.h>
  • std::format to fmt::format

main.cpp

#include <iostream>

#include <fmt/core.h>

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

and compile and run with:

g++ -std=c++11 -o main.out main.cpp -lfmt
./main.out

Output:

10 0x11 18

Related: std::string formatting like sprintf

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 3
    Good to know, but as of almost April 2021, compilers don't support it, even though the standard is out there, maybe it's worth mentioning in this answer. – VP. Mar 29 '21 at 19:46
  • 1
    I am very much waiting for this library to become standard shipping with C++ compilers. – shuhalo May 11 '21 at 17:29
  • Meanwhile, the standard is out and also implementations that support it. The most impressing thing I experienced was that a **compile-time error indicates a mismatch** between format string and arguments. – Wolf Jun 09 '23 at 13:13
9

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..
}
ledonter
  • 1,269
  • 9
  • 27
whacko__Cracko
  • 6,592
  • 8
  • 33
  • 35
1

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/

aGuegu
  • 1,813
  • 1
  • 21
  • 22
0

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

J. Wilde
  • 31
  • 3