Saving old stream format and restoring it

Discussion in 'C++' started by Marcus Kwok, Feb 17, 2006.

  1. Marcus Kwok

    Marcus Kwok Guest

    How do you save the formatting options for a stream? In the program
    below, notice that when I define my operator<<() for the custom type, it
    permanently changes the output format of the stream:

    #include <iostream>
    #include <iomanip>

    struct Data {
    double d;
    };

    std::eek:stream&
    operator<<(std::eek:stream& o, const Data& d)
    {
    //std::eek:stream old;
    //old.copyfmt(o);
    o << "during: " << std::fixed << std::setprecision(3) << d.d;
    //o.copyfmt(old);
    return o;
    }

    int main()
    {
    Data d;
    d.d = 3.14159;

    double dd;
    dd = 3.14159;
    std::cout << "before: " << dd << '\n';
    std::cout << d << '\n';
    std::cout << " after: " << dd << '\n';

    return 0;
    }

    output:
    before: 3.14159
    during: 3.142
    after: 3.142


    When I uncomment the lines in operator<<(), I get a "no appropriate
    default constructor available" error, and when I tried

    std::eek:stream old(o);

    I get a "no copy constructor available or copy constructor is declared
    'explicit'" error.


    So, how do I save the old formatting options for the stream, and restore
    them before returning?

    --
    Marcus Kwok
    Marcus Kwok, Feb 17, 2006
    #1
    1. Advertising

  2. Marcus Kwok

    Kai-Uwe Bux Guest

    Marcus Kwok wrote:

    > How do you save the formatting options for a stream? In the program
    > below, notice that when I define my operator<<() for the custom type, it
    > permanently changes the output format of the stream:
    >
    > #include <iostream>
    > #include <iomanip>
    >
    > struct Data {
    > double d;
    > };
    >
    > std::eek:stream&
    > operator<<(std::eek:stream& o, const Data& d)
    > {
    > //std::eek:stream old;
    > //old.copyfmt(o);
    > o << "during: " << std::fixed << std::setprecision(3) << d.d;
    > //o.copyfmt(old);
    > return o;
    > }
    >
    > int main()
    > {
    > Data d;
    > d.d = 3.14159;
    >
    > double dd;
    > dd = 3.14159;
    > std::cout << "before: " << dd << '\n';
    > std::cout << d << '\n';
    > std::cout << " after: " << dd << '\n';
    >
    > return 0;
    > }
    >
    > output:
    > before: 3.14159
    > during: 3.142
    > after: 3.142
    >
    >
    > When I uncomment the lines in operator<<(), I get a "no appropriate
    > default constructor available" error, and when I tried
    >
    > std::eek:stream old(o);
    >
    > I get a "no copy constructor available or copy constructor is declared
    > 'explicit'" error.
    >
    >
    > So, how do I save the old formatting options for the stream, and restore
    > them before returning?
    >


    Just don't change them:

    #include <iostream>
    #include <iomanip>
    #include <sstream>

    struct Data {
    double d;
    };

    std::eek:stream&
    operator<<(std::eek:stream& o, const Data& d)
    {
    std::stringstream str;
    str << "during: " << std::fixed << std::setprecision(3) << d.d;
    o << str.str();
    return o;
    }

    int main()
    {
    Data d;
    d.d = 3.14159;

    double dd;
    dd = 3.14159;
    std::cout << "before: " << dd << '\n';
    std::cout << d << '\n';
    std::cout << " after: " << dd << '\n';

    return 0;
    }


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Feb 17, 2006
    #2
    1. Advertising

  3. Marcus Kwok wrote:
    > std::eek:stream&
    > operator<<(std::eek:stream& o, const Data& d)
    > {
    > //std::eek:stream old;


    Use 'std::eek:stream old(0);' instead: the constructor of 'std::eek:stream'
    requires a stream buffer but this can be null.
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.eai-systems.com> - Efficient Artificial Intelligence
    Dietmar Kuehl, Feb 17, 2006
    #3
  4. Kai-Uwe Bux wrote:
    > Just don't change them:


    > std::eek:stream&
    > operator<<(std::eek:stream& o, const Data& d)
    > {
    > std::stringstream str;
    > str << "during: " << std::fixed << std::setprecision(3) << d.d;
    > o << str.str();
    > return o;
    > }


    This doesn't work: for example, when called using code like this
    it behaves in unexpected ways:

    std::cout << std::showpos << d;
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.eai-systems.com> - Efficient Artificial Intelligence
    Dietmar Kuehl, Feb 17, 2006
    #4
  5. Marcus Kwok

    Neil Cerutti Guest

    On 2006-02-17, Dietmar Kuehl <> wrote:
    > Marcus Kwok wrote:
    >> std::eek:stream&
    >> operator<<(std::eek:stream& o, const Data& d)
    >> {
    >> //std::eek:stream old;

    >
    > Use 'std::eek:stream old(0);' instead: the constructor of 'std::eek:stream'
    > requires a stream buffer but this can be null.


    I was going to suggest:

    std::eek:stream::ios_type old;

    The docs say it can't be used until init is called, but it's not clear
    if that means you can't simply copy format information in and then out
    again.

    If you wind up needing to call init before copyfmt, then yucky.

    --
    Neil Cerutti
    A billion here, a billion there, sooner or later it adds up to
    real money. --Everett Dirksen
    Neil Cerutti, Feb 17, 2006
    #5
  6. Neil Cerutti wrote:

    > I was going to suggest:
    >
    > std::eek:stream::ios_type old;


    I have no idea what the above is...? Are you referring to
    'std::ios_base'? This cannot hold the complete format and I
    don't think it is equipped with a 'copyfmt()' member function.
    The other candidate would be 'std::ios'. However:

    > If you wind up needing to call init before copyfmt, then yucky.


    The design of the initialization of 'std::ios_base' and 'std::ios'
    sucks^H^H^H^H^His suboptimal and you indeed need to call 'init()'
    before you can do anything to 'std::ios'. In particular, a call
    to 'init()' is strictly required even to destruct the object (the
    standard is explicit about this in lib.basic.ios.cons paragraph 2,
    second sentence).
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.eai-systems.com> - Efficient Artificial Intelligence
    Dietmar Kuehl, Feb 17, 2006
    #6
  7. Marcus Kwok

    Marcus Kwok Guest

    Dietmar Kuehl <> wrote:
    > Marcus Kwok wrote:
    >> std::eek:stream&
    >> operator<<(std::eek:stream& o, const Data& d)
    >> {
    >> //std::eek:stream old;

    >
    > Use 'std::eek:stream old(0);' instead: the constructor of 'std::eek:stream'
    > requires a stream buffer but this can be null.


    Nice, this seems to work great. Thanks.

    --
    Marcus Kwok
    Marcus Kwok, Feb 17, 2006
    #7
  8. Marcus Kwok wrote:
    > Dietmar Kuehl <> wrote:
    >> Use 'std::eek:stream old(0);' instead: the constructor of 'std::eek:stream'
    >> requires a stream buffer but this can be null.

    >
    > Nice, this seems to work great. Thanks.


    Note, however, this creation of a stream object is relatively
    involved. At the very least it initialized quite a few member
    variables and it might even do memory allocations. Thus, if you
    need to save the format frequently you might want to consider
    using just one stream object, e.g. by using a function static
    object:

    {
    static std::eek:stream old(0);
    ...
    }

    This object will only be constructed once. Of course, it will
    also cause problems in multi-threaded code.
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.eai-systems.com> - Efficient Artificial Intelligence
    Dietmar Kuehl, Feb 17, 2006
    #8
  9. Marcus Kwok

    Neil Cerutti Guest

    On 2006-02-17, Dietmar Kuehl <> wrote:
    > Neil Cerutti wrote:
    >
    >> I was going to suggest:
    >>
    >> std::eek:stream::ios_type old;

    >
    > I have no idea what the above is...? Are you referring to
    > 'std::ios_base'? This cannot hold the complete format and I
    > don't think it is equipped with a 'copyfmt()' member function.
    > The other candidate would be 'std::ios'. However:


    Yes, thanks for the correction. I had meant to use a basic_ios type.

    >> If you wind up needing to call init before copyfmt, then yucky.

    >
    > The design of the initialization of 'std::ios_base' and 'std::ios'
    > sucks^H^H^H^H^His suboptimal and you indeed need to call 'init()'
    > before you can do anything to 'std::ios'. In particular, a call
    > to 'init()' is strictly required even to destruct the object (the
    > standard is explicit about this in lib.basic.ios.cons paragraph 2,
    > second sentence).


    So there's a default constructor because...

    No wonder Stroustrup doesn't cover this stuff. ;-)

    --
    Neil Cerutti
    Neil Cerutti, Feb 17, 2006
    #9
  10. Marcus Kwok

    Marcus Kwok Guest

    Dietmar Kuehl <> wrote:
    > Marcus Kwok wrote:
    >> Dietmar Kuehl <> wrote:
    >>> Use 'std::eek:stream old(0);' instead: the constructor of 'std::eek:stream'
    >>> requires a stream buffer but this can be null.

    >>
    >> Nice, this seems to work great. Thanks.

    >
    > Note, however, this creation of a stream object is relatively
    > involved. At the very least it initialized quite a few member
    > variables and it might even do memory allocations. Thus, if you
    > need to save the format frequently you might want to consider
    > using just one stream object, e.g. by using a function static
    > object:
    >
    > {
    > static std::eek:stream old(0);
    > ...
    > }
    >
    > This object will only be constructed once. Of course, it will
    > also cause problems in multi-threaded code.


    Oh, I see. So, for example, if I had a

    std::vector<Data> v;

    and did a

    std::copy(v.begin(), v.end(), std::eek:stream_iterator<Data>(std::cout, "\n"));

    then it would have to create/destroy a new std::eek:stream for every
    element in the vector, correct? That does seem like quite a bit of
    overhead.

    The static member/multithreading issue is also significant, but since
    that is OT here (until they add concurrency to the standard) I can defer
    that argument to another place and time.

    It would be nice if the standard had a lightweight "format" class to
    store this in.

    This question was mainly academic for me, and due to the two issues
    above, it looks like it may not be possible to have a completely
    satisfactory solution that can be used in production code. I guess I
    should just stick to explicitly formatting where needed.

    --
    Marcus Kwok
    Marcus Kwok, Feb 17, 2006
    #10
  11. Marcus Kwok

    Jeff Flinn Guest

    Jeff Flinn, Feb 17, 2006
    #11
  12. Marcus Kwok

    Kai-Uwe Bux Guest

    Dietmar Kuehl wrote:

    > Kai-Uwe Bux wrote:
    >> Just don't change them:

    >
    >> std::eek:stream&
    >> operator<<(std::eek:stream& o, const Data& d)
    >> {
    >> std::stringstream str;
    >> str << "during: " << std::fixed << std::setprecision(3) << d.d;
    >> o << str.str();
    >> return o;
    >> }

    >
    > This doesn't work: for example, when called using code like this
    > it behaves in unexpected ways:
    >
    > std::cout << std::showpos << d;


    Good catch. Thanks.

    So, what about:

    std::eek:stream&
    operator<<(std::eek:stream& o, const Data& d)
    {
    std::stringstream str;
    str.copyfmt(o);
    str << "during: " << std::fixed << std::setprecision(3) << d.d;
    o << str.str();
    return o;
    }

    Although, that is probably less efficient than saving the old streams state
    and reinstalling it afterwards.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Feb 18, 2006
    #12
  13. Marcus Kwok

    Csaba Guest

    "Jeff Flinn" <> wrote in news:dt57kp$l2s$1
    @bluegill.adi.com:

    > Marcus Kwok wrote:
    >> How do you save the formatting options for a stream? In the program

    >
    > See the boost io_state_saver library at
    > http://www.boost.org/libs/io/doc/ios_state.html
    >


    Egad, these guys have a library for everything !
    :)

    --
    Life is complex, with real and imaginary parts.
    Csaba, Feb 18, 2006
    #13
  14. Marcus Kwok wrote:
    > Oh, I see. So, for example, if I had a
    >
    > std::vector<Data> v;
    >
    > and did a
    >
    > std::copy(v.begin(), v.end(), std::eek:stream_iterator<Data>(std::cout,
    > "\n"));
    >
    > then it would have to create/destroy a new std::eek:stream for every
    > element in the vector, correct? That does seem like quite a bit of
    > overhead.


    Indeed. Of course, the above vector is empty so no harm is done :)

    > The static member/multithreading issue is also significant, but since
    > that is OT here (until they add concurrency to the standard) I can defer
    > that argument to another place and time.


    I haven't played with it but in theory, at least, you could use a
    pointer to stream in thread local storage. In addition, you might,
    of course, put the state restoration code not into the formatting
    function but into the calling function.

    > It would be nice if the standard had a lightweight "format" class to
    > store this in.


    Yes, indeed. Boost has apparently something but I haven't used that
    class either.
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.eai-systems.com> - Efficient Artificial Intelligence
    Dietmar Kuehl, Feb 18, 2006
    #14
  15. Kai-Uwe Bux wrote:
    > So, what about:
    >
    > std::eek:stream&
    > operator<<(std::eek:stream& o, const Data& d)
    > {
    > std::stringstream str;
    > str.copyfmt(o);
    > str << "during: " << std::fixed << std::setprecision(3) << d.d;
    > o << str.str();
    > return o;
    > }
    >
    > Although, that is probably less efficient than saving the old streams
    > state and reinstalling it afterwards.


    Indeed: it even constructs at least one more object requiring
    dynamic memory allocation (the string). In fact, with the given
    changes of merely setting the formatting flags and the precision,
    it might be best to simply restore just them:

    std::eek:stream&
    operator<< (std::eek:stream& o, Data const& d)
    {
    std::ios_base::fmtflags flags = o.setf(std::ios_base::fixed);
    std::streamsize precision = o.precision(3);
    o << "during: " << d.d;
    o.precision(precision);
    o.flags(flags);
    }
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.eai-systems.com> - Efficient Artificial Intelligence
    Dietmar Kuehl, Feb 19, 2006
    #15
  16. Marcus Kwok

    Marcus Kwok Guest

    Dietmar Kuehl <> wrote:
    > Kai-Uwe Bux wrote:
    >> So, what about:
    >>
    >> std::eek:stream&
    >> operator<<(std::eek:stream& o, const Data& d)
    >> {
    >> std::stringstream str;
    >> str.copyfmt(o);
    >> str << "during: " << std::fixed << std::setprecision(3) << d.d;
    >> o << str.str();
    >> return o;
    >> }
    >>
    >> Although, that is probably less efficient than saving the old streams
    >> state and reinstalling it afterwards.

    >
    > Indeed: it even constructs at least one more object requiring
    > dynamic memory allocation (the string). In fact, with the given
    > changes of merely setting the formatting flags and the precision,
    > it might be best to simply restore just them:
    >
    > std::eek:stream&
    > operator<< (std::eek:stream& o, Data const& d)
    > {
    > std::ios_base::fmtflags flags = o.setf(std::ios_base::fixed);
    > std::streamsize precision = o.precision(3);
    > o << "during: " << d.d;
    > o.precision(precision);
    > o.flags(flags);
    > }


    This seems elegant; only saving and restoring the things that get
    modified.

    --
    Marcus Kwok
    Marcus Kwok, Feb 20, 2006
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    330
    Steve C. Orr [MVP, MCSD]
    Jan 12, 2004
  2. Jacob H
    Replies:
    4
    Views:
    367
    M.E.Farmer
    Jan 25, 2005
  3. Wolfgang Thomsen

    Saving and restoring streampos's

    Wolfgang Thomsen, Apr 25, 2007, in forum: C++
    Replies:
    1
    Views:
    381
    James Kanze
    Apr 26, 2007
  4. Ben Giddings

    Saving and restoring with YAML

    Ben Giddings, Oct 1, 2003, in forum: Ruby
    Replies:
    2
    Views:
    107
    Ben Giddings
    Oct 1, 2003
  5. Andreas Drop

    Saving and Restoring a GTK:TreeModel

    Andreas Drop, Apr 10, 2010, in forum: Ruby
    Replies:
    0
    Views:
    97
    Andreas Drop
    Apr 10, 2010
Loading...

Share This Page