Go Back   Rhinocerus > Newsgroup > Newsgroup comp.language.c++ > Newsgroup comp.language.c++.moderated

Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old 10-20-2005, 01:51 PM
bgneal@gmail.com
Guest
 
Posts: n/a
Default streambuf, badbit, and exceptions

I am trying to write a custom streambuf and figure all of this IOStream
stuff out. In my custom streambuf, the underlying transport that I am
encapsulating can fail on me. I would like to communicate this to the
user by having the badbit get set when this happens.

It is not entirely clear to me how a streambuf can cause the badbit to
get set in the "owner" stream. After doing some googling, it looks like
this can be achieved if the streambuf throws an exception from one of
its operations.

Is this correct?

I wrote a test program to see if this works:

#include <iostream>
#include <ostream>
#include <istream>
#include <stdexcept>

class DumbStreambuf : public std::streambuf
{
public:

protected:
virtual int underflow()
{
std::cout << "In underflow" << std::endl;
throw std::runtime_error("DumbStreambuf underflow");
}

virtual int overflow(int /*c*/)
{
std::cout << "In overflow" << std::endl;
throw std::runtime_error("DumbStreambuf overflow");
}
};

int main()
{
DumbStreambuf ds;
std::iostream ios(&ds);

unsigned long bits = ios.exceptions();
std::cout << "bits = " << std::hex << bits << std::dec << std::endl;

try
{
int n;
ios >> n;
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}

std::cout << std::boolalpha <<
"good = " << ios.good() <<
" bad = " << ios.bad() <<
" eof = " << ios.eof() <<
" fail = " << ios.fail() << std::endl;

ios.clear();

try
{
int n = 0;
ios << n;
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}

std::cout << std::boolalpha <<
"good = " << ios.good() <<
" bad = " << ios.bad() <<
" eof = " << ios.eof() <<
" fail = " << ios.fail() << std::endl;

return 0;
}

Here is the output that I get when I build this with g++ 3.4.4 under
Cygwin.

$ ./test
bits = 0
In underflow
Exception: DumbStreambuf underflow
good = true bad = false eof = false fail = false
In overflow
good = false bad = true eof = false fail = true

It looks like that if my streambuf throws an exception during a write
operation (overflow), the exception is caught and the bad bit is set.

But during an input operation (underflow), the bad bit is not getting
set, and my exception is either escaping or getting caught and
re-thrown.

Is this behavior correct? If so, why the asymmetry?

I looked at the STL implementation, and I did see a try/catch block in
the operator>>(int&) function...I'm really confused...

Thanks,
BN


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
Alt Today
Advertising
 
and become member of Rhinocerus
Standard Sponsored Links

  #2 (permalink)  
Old 10-21-2005, 04:29 PM
Maxim Yegorushkin
Guest
 
Posts: n/a
Default Re: streambuf, badbit, and exceptions


bgneal@gmail.com wrote:
> I am trying to write a custom streambuf and figure all of this IOStream
> stuff out. In my custom streambuf, the underlying transport that I am
> encapsulating can fail on me. I would like to communicate this to the
> user by having the badbit get set when this happens.
>
> It is not entirely clear to me how a streambuf can cause the badbit to
> get set in the "owner" stream. After doing some googling, it looks like
> this can be achieved if the streambuf throws an exception from one of
> its operations.
>
> Is this correct?


If I read the standard correctly, overflow() may throw an exception,
while underflow() and uflow() may not.

On failure underflow(), uflow() and overflow() may simply return
traits::eof() as it's stated in §27.5.2.4. For xsputn(), xsgetn() on
failure return 0.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #3 (permalink)  
Old 10-22-2005, 03:24 PM
Brian Neal
Guest
 
Posts: n/a
Default Re: streambuf, badbit, and exceptions

Maxim Yegorushkin wrote:
> bgneal@gmail.com wrote:
> > It is not entirely clear to me how a streambuf can cause the badbit to
> > get set in the "owner" stream. After doing some googling, it looks like
> > this can be achieved if the streambuf throws an exception from one of
> > its operations.
> >
> > Is this correct?

>
> If I read the standard correctly, overflow() may throw an exception,
> while underflow() and uflow() may not.


I'm not sure this is correct...see below. But I do see where the
standard explicitly mentions overflow() throwing an exception, and not
for underflow(). But it doesn't say you cannot. :-)

The Lanker & Kreft book also seems to indicate it is okay for
underflow() to throw.

>
> On failure underflow(), uflow() and overflow() may simply return
> traits::eof() as it's stated in §27.5.2.4. For xsputn(), xsgetn() on
> failure return 0.


But if you return traits::eof() from underflow() or uflow(), then only
the eof bit will be set, not badbit. My question remains, how can a
streambuf cause the badbit to be set on the owner stream on input?

I found the following in the standard:

Table 85:
"badbit indicates a loss of integrity in an input or output sequence
(such as an irrecoverable read error from a file);"

That is exactly what I want: badbit to be set on an irrecoverable read
error from my transport.

In 26.6.1.1:

"If rdbuf()->sbumpc() or rdbuf()->sgetc() returns traits::eof(), then
the input function, except as explicitly noted otherwise, completes its
actions and does setstate(eofbit), which may throw ios_base::failure
(27.4.4.3), before returning.

If one of these called functions throws an exception, then unless
explicitly noted otherwise, the input function sets badbit in error
state. If badbit is on in exception(), the input function rethrows the
exception without completing its actions, otherwise it does not throw
anything and proceeds as if the called function had returned a failure
indication."

The phrase "one of these called functions" is kind of vague, but I
think you can count rdbuf()->sgetc() as one of them. That would
eventually call underflow(), and that implies it may throw an
exception. It then seems to imply that the exception should be caught
by the iostream, so that it could set the badbit. Then, only if the
badbit is on in the exceptions() flag, would it rethrow.

I'm beginning to think I'm seeing a bug in g++'s IOStreams
implementation. They've got the output case right, but an exception
during underflow() doesn't seem to work right.

Thanks,
BN


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #4 (permalink)  
Old 10-23-2005, 10:13 AM
James Kanze
Guest
 
Posts: n/a
Default Re: streambuf, badbit, and exceptions

Maxim Yegorushkin wrote:
> bgneal@gmail.com wrote:


>>I am trying to write a custom streambuf and figure all of this
>>IOStream stuff out. In my custom streambuf, the underlying
>>transport that I am encapsulating can fail on me. I would like
>>to communicate this to the user by having the badbit get set
>>when this happens.


>>It is not entirely clear to me how a streambuf can cause the
>>badbit to get set in the "owner" stream. After doing some
>>googling, it looks like this can be achieved if the streambuf
>>throws an exception from one of its operations.


>>Is this correct?


> If I read the standard correctly, overflow() may throw an
> exception, while underflow() and uflow() may not.


Where do you see this? As far as I know, all of the functions
of streambuf (except the destructor) may throw anything they
want.

> On failure underflow(), uflow() and overflow() may simply
> return traits::eof() as it's stated in §27.5.2.4. For
> xsputn(), xsgetn() on failure return 0.


The problem is that there may be different reasons for failure.
Returning EOF, particularly in the case of underflow(), is
interpreted to mean end of file. If you have a hardware read
error, what do you do?

--
James Kanze mailto: james.kanze@free.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #5 (permalink)  
Old 10-25-2005, 01:20 PM
Brian Neal
Guest
 
Posts: n/a
Default Re: streambuf, badbit, and exceptions

I earlier wrote:

> It is not entirely clear to me how a streambuf can cause the badbit to
> get set in the "owner" stream. After doing some googling, it looks like
> this can be achieved if the streambuf throws an exception from one of
> its operations.
>
> Is this correct?


I think so now after the few replies and looking at the standard.

>
> I wrote a test program to see if this works:


<snip>

>
> It looks like that if my streambuf throws an exception during a write
> operation (overflow), the exception is caught and the bad bit is set.
>
> But during an input operation (underflow), the bad bit is not getting
> set, and my exception is either escaping or getting caught and
> re-thrown.
>
> Is this behavior correct? If so, why the asymmetry?


I finally got a chance to try this code on the Visual Studio 2003 .net
compiler and it seems to work as expected. Maybe g++ 3.4.4 (cygwin) has
a bug in it's IOStreams implementation then.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off




All times are GMT. The time now is 05:05 PM.


Copyright ©2009

LinkBacks Enabled by vBSEO 3.3.0 RC2 © 2009, Crawlability, Inc.