basic_ios::init: multiple call standard conform?  
Author Message
Talisker





PostPosted: Fri Feb 11 13:29:35 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

The code below causes a memory leak on Microsoft Visual C++ .NET 2003,
but works fine with GCC 3.3.3 (cygwin special). If I compile with
-DSINGLE_BASIC_IOS_INIT, the memory leak disappears.

It seems that trhe problem comes from calling basic_ios::init twice,
in particular via std::ios(this) and via std::ostream(this). What does
the standard say: is it allowed to call basic_ios::init twice? What
compiler is standard conform, what code version is standard conform?
In particular ist the call of

std::ios(this),

before

std::ostream(this)

obligatory, optional, or bad?


Helmut

======================================================
//
// Based on

// Betrifft:Re: strstream vs. streambuf
// Newsgroups:de.comp.lang.iso-c++
// Datum:2002-03-26 12:21:07 PST
//
#include <iostream>
struct membuf: public std::streambuf
{
membuf(char* pBase,
std::streambuf::int_type pSize,
std::streambuf::int_type pOff);
};

membuf::membuf(char* pBase,
std::streambuf::int_type pSize,
std::streambuf::int_type pOff)
{
setp(pBase, pBase + pSize);
pbump(pOff);
}

static int count = 0;
struct memstream: private virtual membuf, public std::ostream
{
memstream(char* pBase,
std::streambuf::int_type pSize,
std::streambuf::int_type pOff = 0);
~memstream() {++count;} // To prevent optimization
};

memstream::memstream(char* pBase,
std::streambuf::int_type pSize,
std::streambuf::int_type pOff)
: membuf(pBase, pSize, pOff),
#ifndef SINGLE_BASIC_IOS_INIT
std::ios(this),
#endif
std::ostream(this)
{
}

static char buffstr[8192];
int main(int argc,const char* argv[]){
char c;
for(int j=0; j<10; j++)
{
for(int i=0; i<100000; i++)
{
memstream* ms = new memstream(buffstr,8191);
delete ms;
}
std::cout << count << ":";
std::cin >> c;
}
return 0;
}


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.hide-link.com/ ]

Visual Studio158  
 
 
P





PostPosted: Fri Feb 11 13:29:35 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?


> The code below causes a memory leak on Microsoft Visual C++ .NET 2003,
> but works fine with GCC 3.3.3 (cygwin special). If I compile with
> -DSINGLE_BASIC_IOS_INIT, the memory leak disappears.
>
> It seems that trhe problem comes from calling basic_ios::init twice,
> in particular via std::ios(this) and via std::ostream(this). What does
> the standard say: is it allowed to call basic_ios::init twice? What
> compiler is standard conform, what code version is standard conform?

The purpose of basic_ios::init is to properly initialize the object
*after* you construct it, *before* you use it, and most certainly
*before* you destroy it. Since all members of the constructed object
are perforce uninitialized, there is no way to tell whether you've
already called basic_ios::init for the second time. (Yes, I'm sure
that many of us can contrive *some* way to tell, but not one with
practical utility commensurate with its cost.)

So I think it's a reasonable interpretation of the C++ Standard that
you should not call basic_ios::init twice for the same object.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
zei2003d





PostPosted: Sun Feb 13 15:23:39 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

> The purpose of basic_ios::init is to properly initialize the object
> *after* you construct it, *before* you use it, and most certainly
> *before* you destroy it. Since all members of the constructed object
> are perforce uninitialized, there is no way to tell whether you've
> already called basic_ios::init for the second time.

How do you know in the destructor whether the members must or must not
be destroyed?

> So I think it's a reasonable interpretation of the C++ Standard that
> you should not call basic_ios::init twice for the same object.

So you mean the standard is ambigous?

Helmut

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
pjp





PostPosted: Sun Feb 13 19:02:41 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?



>
>> The purpose of basic_ios::init is to properly initialize the object
>> *after* you construct it, *before* you use it, and most certainly
>> *before* you destroy it. Since all members of the constructed object
>> are perforce uninitialized, there is no way to tell whether you've
>> already called basic_ios::init for the second time.
>
> How do you know in the destructor whether the members must or must not be
> destroyed?

You have to assume that they must be destroyed in the destructor.
That's why they ****y well better be constructed before the
destructor gets called.

>> So I think it's a reasonable interpretation of the C++ Standard that
>> you should not call basic_ios::init twice for the same object.
>
> So you mean the standard is ambigous?

I mean the C++ Standard is not always as clear as it could be. In
this particular case, I believe it was clearer when I first wrote
that part in 1994, but it benefited from the services of multiple
editors thereafter.

P.J. Plauger
Dinkumware, Ltd.
http://www.hide-link.com/


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.hide-link.com/ ]

 
 
zei2003d





PostPosted: Mon Feb 14 00:12:29 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

>>How do you know in the destructor whether the members must or must not be
>>destroyed?
>
>
> You have to assume that they must be destroyed in the destructor.
> That's why they ****y well better be constructed before the
> destructor gets called.

Does this mean, I have to call

std::ios(this),

before

std::ostream(this)

because otherwise I will have problems when std::ostream(this) throws an
exception?

Helmut

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.hide-link.com/ ]

 
 
kanze





PostPosted: Mon Feb 14 06:08:24 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?



> > The code below causes a memory leak on Microsoft Visual C++
> > .NET 2003, but works fine with GCC 3.3.3 (cygwin
> > special). If I compile with -DSINGLE_BASIC_IOS_INIT, the
> > memory leak disappears.

> > It seems that trhe problem comes from calling
> > basic_ios::init twice, in particular via std::ios(this) and
> > via std::ostream(this). What does the standard say: is it
> > allowed to call basic_ios::init twice? What compiler is
> > standard conform, what code version is standard conform?

> The purpose of basic_ios::init is to properly initialize the
> object *after* you construct it, *before* you use it, and most
> certainly *before* you destroy it. Since all members of the
> constructed object are perforce uninitialized, there is no way
> to tell whether you've already called basic_ios::init for the
> second time. (Yes, I'm sure that many of us can contrive
> *some* way to tell, but not one with practical utility
> commensurate with its cost.)

> So I think it's a reasonable interpretation of the C++
> Standard that you should not call basic_ios::init twice for
> the same object.

So how do you avoid calling it twice in a bidirectional stream,
which inherits from both istream and ostream? The only
constructor for istream calls ios::init, and the only
constructor for ostream also calls ios::init.

Read literally, in fact, it would seem that the standard
requires basic_iostream to call basic_ios::init twice. Not that
there's really any way a conforming program could tell. (Read
literally, of course, there are a lot of wierd things in §27.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
pjp





PostPosted: Mon Feb 14 14:22:33 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?





>
>> > The code below causes a memory leak on Microsoft Visual C++
>> > .NET 2003, but works fine with GCC 3.3.3 (cygwin
>> > special). If I compile with -DSINGLE_BASIC_IOS_INIT, the
>> > memory leak disappears.
>
>> > It seems that trhe problem comes from calling
>> > basic_ios::init twice, in particular via std::ios(this) and
>> > via std::ostream(this). What does the standard say: is it
>> > allowed to call basic_ios::init twice? What compiler is
>> > standard conform, what code version is standard conform?
>
>> The purpose of basic_ios::init is to properly initialize the
>> object *after* you construct it, *before* you use it, and most
>> certainly *before* you destroy it. Since all members of the
>> constructed object are perforce uninitialized, there is no way
>> to tell whether you've already called basic_ios::init for the
>> second time. (Yes, I'm sure that many of us can contrive
>> *some* way to tell, but not one with practical utility
>> commensurate with its cost.)
>
>> So I think it's a reasonable interpretation of the C++
>> Standard that you should not call basic_ios::init twice for
>> the same object.
>
> So how do you avoid calling it twice in a bidirectional stream,
> which inherits from both istream and ostream? The only
> constructor for istream calls ios::init, and the only
> constructor for ostream also calls ios::init.

The only *required* constructors behave this way. We add
secret non-initializing constructors to make everything
work.

> Read literally, in fact, it would seem that the standard
> requires basic_iostream to call basic_ios::init twice. Not that
> there's really any way a conforming program could tell. (Read
> literally, of course, there are a lot of wierd things in =A727.)

You'd better let basic_iostream initialize things for you.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
pjp





PostPosted: Mon Feb 14 15:25:20 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?



>
>>>How do you know in the destructor whether the members must or must not be
>>>destroyed?
>>
>>
>> You have to assume that they must be destroyed in the destructor.
>> That's why they ****y well better be constructed before the
>> destructor gets called.
>
> Does this mean, I have to call
>
> std::ios(this),
>
> before
>
> std::ostream(this)
>
> because otherwise I will have problems when std::ostream(this) throws an
> exception?

It means that you'd better find some way of calling basic_ios::init
exactly once after you construct the object and before you do anything
with it, including destroy it.

Look, this is a kludgy mechanism that's overspecified in the C++
Standard. It memorializes the eariest implementation of iostreams,
which used the "nifty counter" technique to ensure that iostreams
objects get constructed exactly once and destroyed exactly once,
even though they appear to be double constructed. If you don't
copy the usage in cin/cout/etc. exactly, you'll almost certainly
do something wrong.

P.J. Plauger
Dinkumware, Ltd.
http://www.hide-link.com/


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.hide-link.com/ ]

 
 
zei2003d





PostPosted: Tue Feb 15 09:45:41 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

> The only *required* constructors behave this way. We add
> secret non-initializing constructors to make everything
> work.

What do you think about this:

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html

135. basic_iostream doubly initialized

Section: 27.6.1.5.1 [lib.iostream.cons] Status: NAD Submitter: Howard
Hinnant Date: 6 Mar 1999

"The LWG agreed that the init() function is called twice, but said that
this is harmless and so not a defect in the standard."

As I understand, this means that a multiple call to init is allowed by
the standard. So "secret non-initializing constructors" (what are
these?) are not needed, instead a properly working init() and perhaps a
base class constructor that initializes all critical pointers with zero
should be enough.

Additionally it means that according to the standard the memory leak in
the library used by Microsoft Visual C++ .NET 2003 is a bug, not a feature.

Helmut

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
pjp





PostPosted: Tue Feb 15 19:18:41 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?



>
>> The only *required* constructors behave this way. We add
>> secret non-initializing constructors to make everything
>> work.
>
> What do you think about this:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html
>
> 135. basic_iostream doubly initialized
>
> Section: 27.6.1.5.1 [lib.iostream.cons] Status: NAD Submitter: Howard
> Hinnant Date: 6 Mar 1999
>
> "The LWG agreed that the init() function is called twice, but said that
> this is harmless and so not a defect in the standard."
>
> As I understand, this means that a multiple call to init is allowed by the
> standard. So "secret non-initializing constructors" (what are these?) are
> not needed, instead a properly working init() and perhaps a base class
> constructor that initializes all critical pointers with zero should be
> enough.

No.

> Additionally it means that according to the standard the memory leak in
> the library used by Microsoft Visual C++ .NET 2003 is a bug, not a
> feature.

Your memory leak is almost certainly not caused by your second
call to init(). It happens to be tolerated in our code, even
though I don't think it's a good idea, and it shouldn't allocate
any storage the way you call it, last I looked. You're probably
seeing the result of deferred deallocation of locale facets,
which misleads quite a few leak checkers under Windows.

Neither a feature nor a bug.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
helmut





PostPosted: Wed Feb 16 23:11:06 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

> Your memory leak is almost certainly not caused by your second
> call to init().

So you agree that a second call of init() is allowed by the standard
(and maybe even required)?

> It happens to be tolerated in our code, even
> though I don't think it's a good idea, and it shouldn't allocate
> any storage the way you call it, last I looked.

Maybe you should now look again.

> You're probably
> seeing the result of deferred deallocation of locale facets,
> which misleads quite a few leak checkers under Windows.

Should I tell this to our customers when our applications crash?

I sent a test program, just try it and you will se a rapid grow of
memory in the process explorer. I am not speeking about ivory tower
problems. After changing from classic to standard streams, our
applications grew with 50MB per week, but they have to run for several
months. During purifying we found that the leak actually is created in
the second call of init. After omitting the "std::ios(this)", the memory
leak disappeared. I hope you agree that for long running real world
programs I have to completey understand what is going on to avoid future
problems.

Helmut

 
 
helmut





PostPosted: Wed Feb 16 23:33:18 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

> Your memory leak is almost certainly not caused by your second
> call to init().

So you agree that a second call of init() is allowed by the standard
(and maybe even required)?

> It happens to be tolerated in our code, even
> though I don't think it's a good idea, and it shouldn't allocate
> any storage the way you call it, last I looked.

Maybe you should now look again.

> You're probably
> seeing the result of deferred deallocation of locale facets,
> which misleads quite a few leak checkers under Windows.

Should I tell this to our customers when our applications crash?

I sent a test program, just try it and you will se a rapid grow of
memory in the process explorer. I am not speeking about ivory tower
problems. After changing from classic to standard streams, our
applications grew with 50MB per week, but they have to run for several
months. During purifying we found that the leak actually is created in
the second call of init. After omitting the "std::ios(this)", the memory
leak disappeared. I hope you agree that for long running real world
programs I have to completey understand what is going on to avoid future
problems.

Helmut

 
 
zei2003d





PostPosted: Thu Feb 17 20:53:11 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?
>
> Your memory leak is almost certainly not caused by your second
> call to init().

So you agree that a second call of init() is allowed by the standard
(and maybe even required)?

> It happens to be tolerated in our code, even
> though I don't think it's a good idea, and it shouldn't allocate
> any storage the way you call it, last I looked.

Maybe you should now look again.

> You're probably
> seeing the result of deferred deallocation of locale facets,
> which misleads quite a few leak checkers under Windows.

Should I tell this to our customers when our applications crash?

I sent a test program, just try it and you will se a rapid grow of
memory in the process explorer. I am not speeking about ivory tower
problems. After changing from classic to standard streams, our
applications grew with 50MB per week, but they have to run for several
months. During purifying we found that the leak actually is created in
the second call of init. After omitting the "std::ios(this)", the memory
leak disappeared. I hope you agree that for long running real world
programs I have to completey understand what is going on to avoid future
problems.

Helmut

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
Tom





PostPosted: Tue Feb 22 12:57:24 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

>
>>> How do you know in the destructor whether the members must or must
>>> not be destroyed?
>>
>>
>>
>> You have to assume that they must be destroyed in the destructor.
>> That's why they ****y well better be constructed before the
>> destructor gets called.
>
>
> Does this mean, I have to call
>
> std::ios(this),
>
> before
>
> std::ostream(this)
>
> because otherwise I will have problems when std::ostream(this) throws an
> exception?

No, since std::ostream should handle this itself. You should default
initialize std::ios (e.g. std::ios()) rather than passing "this"
(alternatively just leave out the initialization). Then ostream::ostream
will make the call to std::ios::init for you, ensuring that it has been
called before destruction. Note that if std::ios::init fails, then it's
up to the implementation to prevent any corruption, since the standard
says that as long as init has been called (successful or not),
destruction is legal.

To summarise, if you derive from std::ostream, you *must*
default-initialize std::ios, since otherwise std::ios::init will be
called twice, resulting in undefined behaviour.

Tom

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.hide-link.com/ ]

 
 
zei2003d





PostPosted: Wed Feb 23 09:44:52 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

> No, since std::ostream should handle this itself.

"should" or "must"? What is the exact wording of the standard?

> Note that if std::ios::init fails, then it's
> up to the implementation to prevent any corruption

Microsoft Visual Studio .NET 2003\Vc7\crt\src\ios.cpp contains the
line

void ios_base::_Init()
{ // initialize a new ios_base
_Ploc = new locale;
...
}

where _Ploc is of type locale*.
How does this prevent corruption in case of a bad_alloc exception,
when _Ploc is not initialized?

Helmut

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
Tom





PostPosted: Mon Feb 28 05:32:33 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?



>
> > No, since std::ostream should handle this itself.
>
> "should" or "must"? What is the exact wording of the standard?

Well, ostream(streambuf*) is required to call basic_ios::init. But are
you asking whether it is allowed to crash if it throws an exception? No
is obviously the answer, as long as the streambuf pointer was a valid
one, and the rest of the program has defined behaviour. Whether it
leaks resources or not is just a QOI issue.

a) ostream(streambuf*) must call basic_ios::init
b) basic_ios::init must be called once during construction (the
standard says nothing about the effect of calling it multiple times, so
you can call it UB)
so
c) your own ostream derived class must not call basic_ios::init.

I think the standard should probably say explicitly that init may only
be called once per object, since it is a bit vague on this point.

> > Note that if std::ios::init fails, then it's
> > up to the implementation to prevent any corruption
>
> Microsoft Visual Studio .NET 2003\Vc7\crt\src\ios.cpp contains the
> line
>
> void ios_base::_Init()
> { // initialize a new ios_base
> _Ploc = new locale;
> ...
> }
>
> where _Ploc is of type locale*.
> How does this prevent corruption in case of a bad_alloc exception,
> when _Ploc is not initialized?

_Init is called by the constructor, so the destructor is not called if
it throws. So it doesn't matter that _Ploc isn't initialized, since its
value isn't touched in the case of an exception.

Tom

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
zei2003d





PostPosted: Thu Mar 03 00:26:26 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?

> I think the standard should probably say explicitly that init may only
> be called once per object, since it is a bit vague on this point.

I think the LWG said already differently:

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html

135. basic_iostream doubly initialized

Section: 27.6.1.5.1 [lib.iostream.cons] Status: NAD Submitter:
Howard
Hinnant Date: 6 Mar 1999

"The LWG agreed that the init() function is called twice, but said
that
this is harmless and so not a defect in the standard."


> > Microsoft Visual Studio .NET 2003\Vc7\crt\src\ios.cpp contains the
> > line
> >
> > void ios_base::_Init()
> > { // initialize a new ios_base
> > _Ploc = new locale;
> > ...
> > }

> _Init is called by the constructor,

Microsoft Visual Studio .NET 2003\Vc7\include\xiosabse,
lines 420 to 423:

protected:
ios_base()
{ // default constructor
}

_Init is *not* called by the constructor of ios_base.

> so the destructor is not called if
> it throws.

So _Init can only be called when ios_base has been constructed
completely and the destructor *is* called when _Init throws.

> So it doesn't matter that _Ploc isn't initialized, since its
> value isn't touched in the case of an exception.

So it does matter that _Ploc isn't initialized, since its value is
touched in the case of an exception.

Helmut

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
Tom





PostPosted: Fri Mar 11 07:24:09 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform? Sorry about the delayed response - I hope you're still reading!




>
> > I think the standard should probably say explicitly that init may
only
> > be called once per object, since it is a bit vague on this point.
>
> I think the LWG said already differently:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html
>
> 135. basic_iostream doubly initialized
>
> Section: 27.6.1.5.1 [lib.iostream.cons] Status: NAD Submitter:
> Howard
> Hinnant Date: 6 Mar 1999
>
> "The LWG agreed that the init() function is called twice, but said
> that
> this is harmless and so not a defect in the standard."

Hmm, so in fact, it should be possible to call init() multiple times,
and Dinkumware have a definite bug.

> > > Microsoft Visual Studio .NET 2003\Vc7\crt\src\ios.cpp contains
the
> > > line
> > >
> > > void ios_base::_Init()
> > > { // initialize a new ios_base
> > > _Ploc = new locale;
> > > ...
> > > }
>
> > _Init is called by the constructor,
>
> Microsoft Visual Studio .NET 2003\Vc7\include\xiosabse,
> lines 420 to 423:
>
> protected:
> ios_base()
> { // default constructor
> }
>
> _Init is *not* called by the constructor of ios_base.
>
> > so the destructor is not called if
> > it throws.
>
> So _Init can only be called when ios_base has been constructed
> completely and the destructor *is* called when _Init throws.

Ah, excellent point. In fact, I just managed to force this bug with the
following code:

#include <iostream>
#include <fstream>
#include <cstdlib>

bool disable_allocation = false;

void* operator new(std::size_t size)
{
if (disable_allocation)
{
throw std::bad_alloc();
}
else
{
return std::malloc(size);
}
}

void operator delete(void* ptr)
{
std::free(ptr);
}

int main()
{
disable_allocation = true;
try
{
std::ofstream ofs("Foo.txt");
}
catch(std::bad_alloc const& ex)
{
std::cout << "Success\n";
}
}

I had to link with the release CRT statically to get my operator new to
be called.

> > So it doesn't matter that _Ploc isn't initialized, since its
> > value isn't touched in the case of an exception.
>
> So it does matter that _Ploc isn't initialized, since its value is
> touched in the case of an exception.

Yup, an access violation occurs. Essentially, _Init needs to start by
0-initializing everything before it trys to do anything that might
throw. basic_ios::init also needs to work in the face of multiple
calls. Are Dinkumware still reading this? A bug report is in order I
think...

Still, none of this changes the fact that ostream derived classes
shouldn't really be calling the non-default basic_ios constructor
themselves, since ostream calls basic_ios::init for them anyway.

Tom

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
pjp





PostPosted: Fri Mar 11 10:04:30 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?


> Yup, an access violation occurs. Essentially, _Init needs to start by
> 0-initializing everything before it trys to do anything that might
> throw. basic_ios::init also needs to work in the face of multiple
> calls. Are Dinkumware still reading this? A bug report is in order I
> think...

I've twice been censored when trying to reply to this thread,
so I have nothing further to contribute.

> Still, none of this changes the fact that ostream derived classes
> shouldn't really be calling the non-default basic_ios constructor
> themselves, since ostream calls basic_ios::init for them anyway.

And that's just the tip of an iceberg which has been repeatedly
ignored in this thread, and by the C++ committee when commenting
on the DR.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

 
 
zei2003d





PostPosted: Tue Mar 15 10:20:43 CST 2005 Top

Visual Studio C++ >> basic_ios::init: multiple call standard conform?


>
> > Yup, an access violation occurs. Essentially, _Init needs to start by
> > 0-initializing everything before it trys to do anything that might
> > throw. basic_ios::init also needs to work in the face of multiple
> > calls. Are Dinkumware still reading this? A bug report is in order I
> > think...
>
> I've twice been censored when trying to reply to this thread,
> so I have nothing further to contribute.

So you agree that there is a bug in the library?

> > Still, none of this changes the fact that ostream derived classes
> > shouldn't really be calling the non-default basic_ios constructor
> > themselves, since ostream calls basic_ios::init for them anyway.
>
> And that's just the tip of an iceberg which has been repeatedly
> ignored in this thread, and by the C++ committee when commenting
> on the DR.

Actually the only problem I see is 27.4.4.1 in the standard dscribing
basic_ios::init() :

"The object must be initialized by calling its init member function.
If it is destroyed before it has been initialized the behavior is
undefined."

IMHO the standard should require at least the basic guarantee for
exception safety; otherwise it is (almost?) impossible to derive from
the standard C++ IO library classes in an exception safe way. Actually
looking at the Dinkumware implementation, it is sufficient to properly
initialize the pointers with zero to achieve the basic guarantee.

With respect to my original question I know agree that calling the
non-default basic_ios constructor is indeed unnecessary, maybe
inefficient, but I still think it is allowed. I do not have any
information why Dietmar Kuehl used this constructor in his example
from 2002-03-26 in de.comp.lang.iso-c++. Maybe he reads this and can
give an answer himself. I just can guess that from the current wording
of the standard, it is risky to leave a basic_ios object in an
inconsistent state, so maybe Dietmar Kuehl decided to call init as
early as possible (in particular, by using the non-default basic_ios
constructor). Does the standard guarantee that the ostream constructor
will not throw before calling basic_ios::init()?

OTOH, if a library implementation cannot offer the basic guarantee in
the default constructor of ios_base it will probably have some issues
with exceptions anyway, so nothing is really gained by using the
non-default basic_ios constructor.

Helmut

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]