|
|||
|
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! ] |
|
|
||||
|
||||
|
|
|
|||
|
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! ] |
|
|||
|
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! ] |
|
|||
|
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! ] |
|
|||
|
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! ] |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|