?
=?ISO-8859-1?Q?Viktor_Lundstr=F6m?=
Hi!
I recently decided to write a streambuf which handles streamed
IO to a device (ie. a socket).
Now, in an effort to move away from C-style IO error handling
(ie. if(read(..) == -1) ...), I decided to make my streambuf raise
exceptions upon device error states.
The code is supposed to run on several platforms, but there seems
to be some inconsistency between the different iostream
implementations. This led me to believe that I'm probably doing
this all wrong.
On win32, if an exception is thrown in underflow/overflow the
exception is encased in a try-catch(...) statement in iostream
and 'eaten', unless the iostream.exceptions(badbit) is set,
in which case my exception is rethrown in its entirety (which
is what I want).
The same code, on Solaris gcc 3.01, results in an exception
always being thrown regardless of iostream.exceptions(badbit).
On RedHat 7.2 (don't know which gcc version) I get a SIGABRT,
regardless of badbit flag.
Should I not be throwing exceptions in the streambuffer?
If so, how do I raise an exception upon error?
On overflow, returning EOF with iostream.exceptions(eofbit) set
does not result in exception on RedHat.
See example code below:
#include <iostream>
using namespace std;
class mybuf: public streambuf {
char oBuf[1024];
public:
static int lastExceptionPtr;
mybuf() {
setp(oBuf, oBuf+1);
}
~mybuf() {
sync();
}
int sync() {
if (pptr() > pbase()) {
// physical write
setp(oBuf, oBuf+1);
}
return 0;
}
int overflow(int c) {
sync();
string *str = new string("exception in overflow");
lastExceptionPtr = (int)str;
throw str;
if (c != EOF) {
*pptr() = static_cast<char>(c);
pbump(1);
}
return c;
}
};
class myio : public ostream {
mybuf buf;
public:
myio() : ostream(&buf) {
}
};
min.cpp:
#include "min.h"
int mybuf::lastExceptionPtr = -1;
int main(int argc, char *argv[]) {
myio stream;
//stream.exceptions(iostream::goodbit); // throw no
exceptions, ever
cout << "Testing throw of exception inside overflow, should
not throw exceptions..." << endl;
try {
stream << "0";
stream << "1";
stream << "2";
stream.flush();
} catch(string *ptr) {
cout << "Stream threw exception, even though it
should not!" << endl;
cout << "Was the exception equal to the one thrown? "
<< ((int)ptr == mybuf::lastExceptionPtr) << endl;
} catch(...) {
cout << "Stream threw undefined exception, even
though it should not! " << endl;
}
cout << "Test done." << endl;
mybuf::lastExceptionPtr = -1;
cout << "Testing throw of exception inside overflow, should
throw exceptions..." << endl;
myio stream2;
stream2.exceptions(iostream::badbit);
try {
stream2 << "0";
stream2 << "1";
stream2 << "2";
stream2.flush();
} catch(string *ptr) {
cout << "Stream threw exception when it should!" <<
endl;
cout << "Was the exception equal to the one thrown? "
<< ((int)ptr == mybuf::lastExceptionPtr) << endl;
}
cout << "Test done." << endl;
return 0;
}
Viktor Lundström
I recently decided to write a streambuf which handles streamed
IO to a device (ie. a socket).
Now, in an effort to move away from C-style IO error handling
(ie. if(read(..) == -1) ...), I decided to make my streambuf raise
exceptions upon device error states.
The code is supposed to run on several platforms, but there seems
to be some inconsistency between the different iostream
implementations. This led me to believe that I'm probably doing
this all wrong.
On win32, if an exception is thrown in underflow/overflow the
exception is encased in a try-catch(...) statement in iostream
and 'eaten', unless the iostream.exceptions(badbit) is set,
in which case my exception is rethrown in its entirety (which
is what I want).
The same code, on Solaris gcc 3.01, results in an exception
always being thrown regardless of iostream.exceptions(badbit).
On RedHat 7.2 (don't know which gcc version) I get a SIGABRT,
regardless of badbit flag.
Should I not be throwing exceptions in the streambuffer?
If so, how do I raise an exception upon error?
On overflow, returning EOF with iostream.exceptions(eofbit) set
does not result in exception on RedHat.
See example code below:
#include <iostream>
using namespace std;
class mybuf: public streambuf {
char oBuf[1024];
public:
static int lastExceptionPtr;
mybuf() {
setp(oBuf, oBuf+1);
}
~mybuf() {
sync();
}
int sync() {
if (pptr() > pbase()) {
// physical write
setp(oBuf, oBuf+1);
}
return 0;
}
int overflow(int c) {
sync();
string *str = new string("exception in overflow");
lastExceptionPtr = (int)str;
throw str;
if (c != EOF) {
*pptr() = static_cast<char>(c);
pbump(1);
}
return c;
}
};
class myio : public ostream {
mybuf buf;
public:
myio() : ostream(&buf) {
}
};
min.cpp:
#include "min.h"
int mybuf::lastExceptionPtr = -1;
int main(int argc, char *argv[]) {
myio stream;
//stream.exceptions(iostream::goodbit); // throw no
exceptions, ever
cout << "Testing throw of exception inside overflow, should
not throw exceptions..." << endl;
try {
stream << "0";
stream << "1";
stream << "2";
stream.flush();
} catch(string *ptr) {
cout << "Stream threw exception, even though it
should not!" << endl;
cout << "Was the exception equal to the one thrown? "
<< ((int)ptr == mybuf::lastExceptionPtr) << endl;
} catch(...) {
cout << "Stream threw undefined exception, even
though it should not! " << endl;
}
cout << "Test done." << endl;
mybuf::lastExceptionPtr = -1;
cout << "Testing throw of exception inside overflow, should
throw exceptions..." << endl;
myio stream2;
stream2.exceptions(iostream::badbit);
try {
stream2 << "0";
stream2 << "1";
stream2 << "2";
stream2.flush();
} catch(string *ptr) {
cout << "Stream threw exception when it should!" <<
endl;
cout << "Was the exception equal to the one thrown? "
<< ((int)ptr == mybuf::lastExceptionPtr) << endl;
}
cout << "Test done." << endl;
return 0;
}
Viktor Lundström