Topic: Stream ownership of streambuf


Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Wed, 12 Jun 2002 18:26:26 GMT
Raw View
"Raoul Gough" <RaoulGough@yahoo.co.uk> wrote in message news:<ae5qsk$47kos$1@ID-136218.news.dfncis.de>...
> I've been trying to understand stream ownership of stream buffers, but
> haven't been able to find out where the standard specifies when and where a
> streambuf gets destroyed. For example, in the following code either stream1
> or stream2 (but not both) should clean up the shared streambuf:
>
> std::ostringstream stream1;
> std::ostringstream stream2;
> stream2.rdbuf (stream1.rdbuf());

You are mixing two things here:
- Ownership of streams in derived stream classes. This is very simple: whether
  a derived stream owns the underlying stream buffer depends on the derived
  class :-) For the standard stream classes, ie. the file stream, string
  stream, and char-array stream classes, the stream buffer is owned by the
  constructing stream object. In general, derived stream classes are basically
  a convenience approach to construction of stream with a specific stream
  buffer, I would expect that each derived stream object owns a stream buffer
  object, too.
- Ownership of the stream base classes. This is even simpler: The base classes
  never own a stream buffer. They just maintain an intance via the 'rdbuf()'
  functions.

Conceptually, there are two different stream buffers associated with typical
derived streams:
- The stream buffer to which a reference is maintained by the 'rdbuf()'
  functions. This is the stream buffer used for all standard input and output
  functions.
- The initial stream buffer. This stream buffer is initially identical to the
  stream buffer to the stream buffer maintained by the 'rdbuf()' functions.

Note, that derived streams also often have an 'rdbuf()' function which provides
access to the derived stream buffer and which may differ from the stream buffer
maintained by the base class:

  std::ostringstream stream1;
  std::ostringstream stream2;
  assert(stream2.rdbuf() == stream2.std::ostream::rdbuf());
  stream2.std::ostream::rdbuf(stream1.rdbuf());
  assert(stream2.rdbuf() != stream2.std::ostream::rdbuf());

Typically, additional member functions, like the 'str()' functions of the
string stream, or the 'open()', 'close()', etc. functions of the file stream,
access the stream buffer maintained by the derived object, which is not
necessarily the stream buffer used for the I/O functions!

> Presumably the stringstream records whether it owns its stream buffer or
> not. Is this specified somewhere in the standard? What if code does x.rdbuf
> (x.rdbuf())?

The standard suggests in non-normative text that the stream buffer is a member
of the string stream object. Probably most implementation will effectively use
just this approach, although probably in a variation which guarantees early
construction and late destruction. For example, I'm using this in my standard
library implementation (well, basically: the real implementation is all
templatized, of course):

  struct stringstream_pbase {
    stringstream_pbase(std::string const& str): m_sbuf(str) {}
    // ...
    std::stringbuf m_sbuf;
  };

  class ostringstream:
    private virtual stringstream_pbase,
    public std::ostream
  {
    // ...
  };

Using a virtual base class as the first base to hold the actual stream buffer
object guarantees that the stream buffer object is constructed prior to all
other bases, in particular prior to the 'std::ios' subobject which is a virtual
base of 'std::ostream'. The stream buffer is not a base itself to prevent
accidental overriding of virtual functions if a user derives from the
'ostringstream' object (for which there is probably no good reason anyway).

> Also, in "The C++ Standard Library", Josuttis suggests that cout requires a
> valid buffer for correct program exit.

Yes, this is not a suggestion but a hard requirement: The destructor of
'std::ios_base::Init' may flush all standard stream objects (see 27.4.2.1.6).
Flushing the stream objects means that they should either be in an error state
or have a non-destructed stream buffer object installed. That is, it is OK to
use '0' as a stream buffer (for conforming implementation; for some
implementations currently around this is not OK: they really require a stream
buffer) but it is definitely not OK to use a pointer to a destroyed stream
buffer.

> My reading of the standard suggests
> that cout is required to be a basic_ostream<char>, and the only statement I
> can find about ostream destructors at all (27.6.2.2) says that
> ~basic_ostream does not perform any operations on rdbuf(). Wouldn't that
> suggest that cout's buffer can be anything (including 0 or a since-destroyed
> streambuf) at program exit?

If the quoted section were the only statement, this suggestion would probably
be true although it is always a bad idea to keep pointers to destructed objects
floating around deliberately. However, it is not the only section and the
section I quoted is the reason the stream buffer (or '0') is needed.

> e.g. the following crashes on my system:
>
> #include <iostream>
> #include <sstream>
>
> int main ()
> {
>   std::ostringstream stream1;
>   std::cout.rdbuf (stream1.rdbuf());
> }

This may crash on some systems but not on others. Actually, I'm not sure if
the section on the destructor of 'Init' requires a flush of the standard
stream objects at program termination... I would, however, expect that all
implementations actually flush at least the standard stream objects at program
termination.

> Where should I be looking in the standard, or is this kind of thing outside
> its scope?

It is in the standard - somewhere. It is often not enough to look in specific
places but several places may be involved. Which these are depends on what you
are looking for. ... and I'm not sure whether I hit all relevant places in
the above description.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Raoul Gough" <RaoulGough@yahoo.co.uk>
Date: Thu, 13 Jun 2002 23:57:27 GMT
Raw View
"Dietmar Kuehl" <dietmar_kuehl@yahoo.com> wrote in message
news:5b15f8fd.0206120324.34855bd5@posting.google.com...
[snip]
> Note, that derived streams also often have an 'rdbuf()' function which
provides
> access to the derived stream buffer and which may differ from the stream
buffer
> maintained by the base class:
>
>   std::ostringstream stream1;
>   std::ostringstream stream2;
>   assert(stream2.rdbuf() == stream2.std::ostream::rdbuf());
>   stream2.std::ostream::rdbuf(stream1.rdbuf());
>   assert(stream2.rdbuf() != stream2.std::ostream::rdbuf());
>
> Typically, additional member functions, like the 'str()' functions of the
> string stream, or the 'open()', 'close()', etc. functions of the file
stream,
> access the stream buffer maintained by the derived object, which is not
> necessarily the stream buffer used for the I/O functions!

Wow. So potentially I could do:

// After stream2.std::ostream::rdbuf(stream1.rdbuf());
stream2 << "Hello world";

and this _won't_ affect stream2.str() whereas it _will_ affect
stream1.str().

And stream2.std::ostream::rdbuf(stream2.rdbuf()) will restore stream2 to
normal. I was confused, among other things, by thinking that rdbuf() had to
refer to the same buffer in all cases, but of course the ostream versions of
the function are hidden in the derived classes. Added to that, the derived
classes maintain a buffer separately to the base class, and it all makes a
lot more sense.

[snip]

> "Raoul Gough" <RaoulGough@yahoo.co.uk> wrote in message
news:<ae5qsk$47kos$1@ID-136218.news.dfncis.de>...
> > Also, in "The C++ Standard Library", Josuttis suggests that cout
requires a
> > valid buffer for correct program exit.
>
> Yes, this is not a suggestion but a hard requirement: The destructor of
> 'std::ios_base::Init' may flush all standard stream objects (see
27.4.2.1.6).
> Flushing the stream objects means that they should either be in an error
state
> or have a non-destructed stream buffer object installed. That is, it is OK
to
> use '0' as a stream buffer (for conforming implementation; for some
> implementations currently around this is not OK: they really require a
stream
> buffer) but it is definitely not OK to use a pointer to a destroyed stream
> buffer.

Yes, that certainly explains it. Thanks to everyone for the help.

Regards,
Raoul Gough.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Dietmar Kuehl <dietmar_kuehl@phaidros.com>
Date: Fri, 14 Jun 2002 14:16:35 GMT
Raw View
Raoul Gough wrote:
> "Dietmar Kuehl" <dietmar_kuehl@yahoo.com> wrote:
>>   std::ostringstream stream1;
>>   std::ostringstream stream2;
>>   stream2.std::ostream::rdbuf(stream1.rdbuf());

> Wow. So potentially I could do:
> stream2 << "Hello world";
>
> and this _won't_ affect stream2.str() whereas it _will_ affect
> stream1.str().

It may be a little bit complex to track these things down in a program
and thus it is probably not advisable, but, yes, this is what is going
on: The derived classes' 'rdbuf()' always returns the derived stream
buffer (at least for the standard stream classes) and is not affected
by changing the stream buffer using the base classes' 'rdbuf()'
function.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Raoul Gough" <RaoulGough@yahoo.co.uk>
Date: Tue, 11 Jun 2002 21:46:56 GMT
Raw View
I've been trying to understand stream ownership of stream buffers, but
haven't been able to find out where the standard specifies when and where a
streambuf gets destroyed. For example, in the following code either stream1
or stream2 (but not both) should clean up the shared streambuf:

std::ostringstream stream1;
std::ostringstream stream2;
stream2.rdbuf (stream1.rdbuf());

Presumably the stringstream records whether it owns its stream buffer or
not. Is this specified somewhere in the standard? What if code does x.rdbuf
(x.rdbuf())?

Also, in "The C++ Standard Library", Josuttis suggests that cout requires a
valid buffer for correct program exit. My reading of the standard suggests
that cout is required to be a basic_ostream<char>, and the only statement I
can find about ostream destructors at all (27.6.2.2) says that
~basic_ostream does not perform any operations on rdbuf(). Wouldn't that
suggest that cout's buffer can be anything (including 0 or a since-destroyed
streambuf) at program exit?

e.g. the following crashes on my system:

#include <iostream>
#include <sstream>

int main ()
{
  std::ostringstream stream1;
  std::cout.rdbuf (stream1.rdbuf());
}

Where should I be looking in the standard, or is this kind of thing outside
its scope?

Regards,
Raoul Gough.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Jim Fischer" <jfischer110@attbi.com>
Date: Wed, 12 Jun 2002 05:13:24 GMT
Raw View
"Raoul Gough" <RaoulGough@yahoo.co.uk> wrote in message
news:ae5qsk$47kos$1@ID-136218.news.dfncis.de...
> I've been trying to understand stream ownership of stream buffers, but
> haven't been able to find out where the standard specifies when and where
a
> streambuf gets destroyed.

There seems to be a defect report filed on 27.4.4.1, "basic_ios
constructors" due to the fact that the basic_ios class's destructor function
is not listed / explained. See:

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#53

[n.b. On my computer, the URL shown above doesn't automatically "jump down"
to section 53 after the page loads. So after the page loads, you might need
to locate section 53 "by hand"...]


Jim



> For example, in the following code either stream1
> or stream2 (but not both) should clean up the shared streambuf:
>
> std::ostringstream stream1;
> std::ostringstream stream2;
> stream2.rdbuf (stream1.rdbuf());
>
> Presumably the stringstream records whether it owns its stream buffer or
> not. Is this specified somewhere in the standard? What if code does
x.rdbuf
> (x.rdbuf())?
>
> Also, in "The C++ Standard Library", Josuttis suggests that cout requires
a
> valid buffer for correct program exit. My reading of the standard suggests
> that cout is required to be a basic_ostream<char>, and the only statement
I
> can find about ostream destructors at all (27.6.2.2) says that
> ~basic_ostream does not perform any operations on rdbuf(). Wouldn't that
> suggest that cout's buffer can be anything (including 0 or a
since-destroyed
> streambuf) at program exit?
>
> e.g. the following crashes on my system:
>
> #include <iostream>
> #include <sstream>
>
> int main ()
> {
>   std::ostringstream stream1;
>   std::cout.rdbuf (stream1.rdbuf());
> }
>
> Where should I be looking in the standard, or is this kind of thing
outside
> its scope?
>
> Regards,
> Raoul Gough.
>
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]
>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 12 Jun 2002 16:16:14 GMT
Raw View
"Raoul Gough" <RaoulGough@yahoo.co.uk> wrote in message
news:<ae5qsk$47kos$1@ID-136218.news.dfncis.de>...

> I've been trying to understand stream ownership of stream buffers,
> but haven't been able to find out where the standard specifies when
> and where a streambuf gets destroyed. For example, in the following
> code either stream1 or stream2 (but not both) should clean up the
> shared streambuf:

> std::ostringstream stream1;
> std::ostringstream stream2;
> stream2.rdbuf (stream1.rdbuf());

> Presumably the stringstream records whether it owns its stream
> buffer or not. Is this specified somewhere in the standard? What if
> code does x.rdbuf (x.rdbuf())?

I once discussed this with Dietmar Kuehl, and he convinced me that the
standard is relatively clear about this -- each derived ostream class
should destruct the streambuf it created (in its destructor),
regardless of what happens to the streambuf pointer in the base class.

If I recall correctly, he also said something that many
implementations are not conform in this regard:-).

> Also, in "The C++ Standard Library", Josuttis suggests that cout
> requires a valid buffer for correct program exit.

This may simply be because Josuttis is talking about writing programs
which work with existing implementations, and not just about what the
standard requires.

> My reading of the standard suggests that cout is required to be a
> basic_ostream<char>, and the only statement I can find about ostream
> destructors at all (27.6.2.2) says that ~basic_ostream does not
> perform any operations on rdbuf(). Wouldn't that suggest that cout's
> buffer can be anything (including 0 or a since-destroyed streambuf)
> at program exit?

I think it is a bit more subtle.  The standard requires that cout not
be destructed at all.  So any streambuf it constructs should not be
destructed either.  On the other hand, flush() *will* be called
(instead of the destructor).  This means that:
  - that any output preceding exit is guaranteed to be flushed,
  - that if you use cout in destructors of static objects, you should
    call flush yourself, since the automatic flush may have already
    been called, and
  - since flush calls a function on streambuf, cout had better have a
    valid streambuf when exit is called.

> e.g. the following crashes on my system:

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

> int main ()
> {
>   std::ostringstream stream1;
>   std::cout.rdbuf (stream1.rdbuf());
> }

> Where should I be looking in the standard, or is this kind of thing
> outside its scope?

This is an error.  The standard says that the streambuf for stream1
will be destructed when leaving main (see the description of
ostringstream), and that cout will call flush (which will call
streambuf::sync) during the destruction of static objects (see the
description of the ios_base::Init class).

--
James Kanze                                mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)69 63198627

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]