 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
bgneal@gmail.com Guest
|
Posted: Thu Oct 20, 2005 1:51 pm Post subject: 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! ]
|
|
| Back to top |
|
 |
Maxim Yegorushkin Guest
|
Posted: Fri Oct 21, 2005 4:29 pm Post subject: Re: streambuf, badbit, and exceptions |
|
|
[email]bgneal (AT) gmail (DOT) com[/email] wrote:
| Quote: | 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! ]
|
|
| Back to top |
|
 |
Brian Neal Guest
|
Posted: Sat Oct 22, 2005 3:24 pm Post subject: Re: streambuf, badbit, and exceptions |
|
|
Maxim Yegorushkin wrote:
| Quote: | bgneal (AT) gmail (DOT) 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.
| Quote: |
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! ]
|
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Sun Oct 23, 2005 10:13 am Post subject: Re: streambuf, badbit, and exceptions |
|
|
Maxim Yegorushkin wrote:
| Quote: | bgneal (AT) gmail (DOT) 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.
| Quote: | 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: [email]james.kanze (AT) free (DOT) fr[/email]
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! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Mon Oct 24, 2005 12:21 am Post subject: Re: streambuf, badbit, and exceptions |
|
|
Maxim Yegorushkin wrote:
| Quote: |
If I read the standard correctly, overflow() may throw an exception,
while underflow() and uflow() may not.
|
I have a different interpretation. About underflow() the standard says
"If the pending sequence is null then the function returns traits::eof()
to indicate failure." underflow() may fail for other reasons and those
reasons, for example a failed memory allocation, may throw an exception.
This is implictly allowed in virtue of the blanket statement 17.4.4.8/3:
"Any other functions defined in the C++ Standard Library that do not
have an exception-specification may throw implementation-defined
exceptions unless otherwise specified."
I acklowedge that the wording used to describe overflow() can be
misleading as it explicitly reference the possibility to throw as a way
to return failure. This is a case when an extra word brings more
confusion than clarity, in my opinion.
By the way, in footnote 275 (27.5.2.4.3) it's explicitly stated that
underflow() and uflow() may throw an exception on failure.
| Quote: | 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.
|
Correct, but if underflow() throws, the exception shall not be caught by
xsgetn/sgetc/sbumpc and that shall cause badbit to be set, according to
27.6.1.1/4.
HTH,
Ganesh
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Brian Neal Guest
|
Posted: Tue Oct 25, 2005 1:20 pm Post subject: Re: streambuf, badbit, and exceptions |
|
|
I earlier wrote:
| Quote: | 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.
| Quote: |
I wrote a test program to see if this works:
|
<snip>
| Quote: |
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! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|