Topic: Does the basic_ostream::basic_ostream do anything with its arg.
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/17 Raw View
My question: does the constructor basic_ostream::basic_ostream do
anything with its argument? In particular, can I pass it a pointer to a
not yet constructed streambuf? (The same question should be asked of
basic_istream, of course.)
The reason for wanting to do this is obvious: I am deriving from
ostream, and would like to have the streambuf a member variable, rather
than new'ing it each time. But member variables are constructed *after*
base classes, so the streambuf* that I pass to ostream actually points
to raw memory.
This is only a (potential) problem in the constructor; the draft
standard says explicitly that the destructor "does not perform any
operations on rdbuf()", which I presume is precisely to allow the
derived class to destruct the streambuf before the base class
destructors are called.
I think that this is implicitly guaranteed for the constructor as well;
the text concerning the constructor speaks of "assigning initial values
to the base class by calling basic_ios::init". Is this enumeration of
behavior guaranteed to be exhaustive, though, or can the constructor
potentially do other things which result in accessing the streambuf?
(FWIW: none of the implementations I've seen to date seem to access the
streambuf in the constructor.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kuehl@horn.informatik.uni-konstanz.de (Dietmar Kuehl)
Date: 1997/04/17 Raw View
Hi,
James Kanze (james-albert.kanze@vx.cit.alcatel.fr) wrote:
: My question: does the constructor basic_ostream::basic_ostream do
: anything with its argument? In particular, can I pass it a pointer to a
: not yet constructed streambuf? (The same question should be asked of
: basic_istream, of course.)
I think, a good implementation should arrange this to be the case but
then, this may be considered to be too costly. The Nov '96 DWP says
that the constructor calls 'basic_ios::init(sb)'. 'init()' in turn is
not required to initialize anything which requires use of the
'streambuf'.
: The reason for wanting to do this is obvious: I am deriving from
: ostream, and would like to have the streambuf a member variable, rather
: than new'ing it each time. But member variables are constructed *after*
: base classes, so the streambuf* that I pass to ostream actually points
: to raw memory.
You might want to play safe and construct the 'streambuf' before the
base classes. Unfortunately, this might introduce a run-time penalty
due to the virtual inheritance (I haven't measured it yet). Here is how
the 'streambuf' can be constructed prior to the base classes:
struct fstream_pbase
{
filebuf sbuf;
fstream_pbase(char const *fname, ios_base::openmode mode):
sbuf(fname, mode)
{
}
};
class ofstream: virtual private fstream_pbase, public ostream
{
//...
};
(I have dropped the template arguments and 'basic_' prefixes to make
things more readable).
Since virtual bases are constructed in a "depth-first left-to-right"
(class.base.init paragraph 5) order, 'fstream_pbase' is constructed
prior to 'ostream' and ancestors. Thus, the 'filebuf' in
'fstream_pbase' is constructed and can safely passed around. In fact,
this also makes the assertion for the destructor unnecessary: The
'filebuf' remains constructed until the destructors using it are run.
This is a refined version of an approach which I have from Ron Klatchko
(ron@crl.com): He used it to work around the problem that the
destructor of 'ios' in an IOStream implementation kept accessing the
already destructed 'streambuf'.
: This is only a (potential) problem in the constructor; the draft
: standard says explicitly that the destructor "does not perform any
: operations on rdbuf()", which I presume is precisely to allow the
: derived class to destruct the streambuf before the base class
: destructors are called.
Unlike in the construction case this is absolutely necessary: While you
can pass a null pointer on construction (behavior of passing a 0 is
explicitly described in the description of 'ios_base::init()'), there
is not such place for the destruction case (well, you can reseat the
'streambuf' using 'rdbuf(0)'...). An alternate approach to the above
mentioned one is to pass a null pointer and then call 'init(&sbuf)' in
the constructor, where 'sbuf' is a corresponding member of the class.
: I think that this is implicitly guaranteed for the constructor as well;
I always think that it would be a good thing to have an implementation
to do what is most likely to break if there is some freedome: Such an
implementation would eg. just access the 'streambuf' to make sure this
breaks (at least create a Purify warning for accessing non-initialized
data). While this implementation would be really bad for actual code,
it would highlight some [potential] portability problems going
undetected otherwise.
--
<mailto:dietmar.kuehl@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I am a realistic optimist - that's why I appear to be slightly pessimistic
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]