Should I derive from ostrstream?

29 views
Skip to first unread message

Michael Bresnahan

unread,
Nov 6, 1995, 3:00:00 AM11/6/95
to
I have a pair of classes, one that represents and database
context and another that represents a database connection.
Both classes are derived from a base class. The base class
handles errors by, amoung other things, maintaining a state
variable much like class ios does. I want my connection class
to behave much like class ostrstream. I would like to do
things like this:

Dbconn conn;
Dbrow row;

conn << "select * from foo" << ends;

conn.execute();

conn >> row;

As I see it, I could either put a ostrstream object in Dbconn
as a member and provide zillions of operator <<() global
functions, or I could derive from ostrstream. The problem
with deriving from ostrstream is that it introduces a bunch of
clashing names, e.g. state, and member functions that are ios
analogies for member functions of my base class with different
names, e.g. good(), bad(), setstate(), etc... The name
clashes would force me to change names in the base class which
will in turn effect my context class which has nothing to do
with ostrstream. These extra functions will make the
interface of Dbconn confusing. Also, since many of the member
functions in ostrstream are not virtual I worry that even if I
override them they will get called by accident if the object
is ever referenced through a pointer to ostrstream.

Can anyone lend me some advice?

MikeB

--
Michael Bresnahan
3M Company, IT Division

Opinions expressed herein are my own and
do not necessarily represent those of 3M.

Michael Bresnahan

unread,
Nov 6, 1995, 3:00:00 AM11/6/95
to
Oh, one thing I forgot. What I would really like to do, but
can't because the HP compiler doesn't support it, is this:

class Dbconn {
public:
//...
friend template<class T>Dbconn& operator <<( Dbconn&, T&
t);
private:
//...
ostrstream ostr;
};

template<class T>
Dbconn& operator( Dbconn& conn, T& t) {

conn.ostr << t;

Michael Bresnahan

unread,
Nov 6, 1995, 3:00:00 AM11/6/95
to

Ugh, another problem. Both ios and my base class define a
operator void*(). The HP compiler is complaining that it
"cannot merge lists of conversion functions". Is there anyway
around this?

Dietmar Kuehl

unread,
Nov 7, 1995, 3:00:00 AM11/7/95
to
Hi,

The answer to $(Subject) is simple: No! Do not try to derive from
'ostrstream', or any other class derived from 'ostream' or 'istream':
The classes derived from 'ostream' and 'istream' are only present for
convenience and are intended as leaf-classes in the inheritance tree.

If you need output send to another stream, just derive a specialized
class from 'streambuf' which sends the output to the stream requested.
It is not that hard and much easier to maintain.

I became quite trained in typing in the URL of a commented example on
how to derive from a 'streambuf'. Thus here is it again:

http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream

(did you notice how fast I typed this :-) If you don't have access to
WWW just send me an e-mail. I will send you the whole code (if too many
requests are received, I will post the code...).
--
dietma...@uni-konstanz.de
http://www.informatik.uni-konstanz.de/~kuehl
I am a realistic optimist - that's why I appear to be slightly pessimistic

ad...@rzaix13.uni-hamburg.de

unread,
Nov 8, 1995, 3:00:00 AM11/8/95
to
Michael Bresnahan (mbres...@mmm.com) wrote:
> I have a pair of classes, one that represents and database
> context and another that represents a database connection.
> Both classes are derived from a base class. The base class
> handles errors by, amoung other things, maintaining a state
> variable much like class ios does. I want my connection class
> to behave much like class ostrstream. I would like to do
> things like this:

> Dbconn conn;
> Dbrow row;

> conn << "select * from foo" << ends;

> conn.execute();

> conn >> row;

> As I see it, I could either put a ostrstream object in Dbconn
> as a member and provide zillions of operator <<() global
> functions,

I think in your case this might be the best idea. There aren't
quite zillions of functions, and they don't have to be global.
To avoid hours of typing, you can use a good old macro:

#define SHL(X) Dbconn &operator<<(X x) { str << x; return *this; }

class Dbconn
{
public:
SHL(int)
SHL(char *)
// ...

private:
ostrstream str;
// ...
};

Insert as many operator<<() functions (that is, SHL macros) as
you need, or look them up in your <iostream.h> file.

> or I could derive from ostrstream. The problem
> with deriving from ostrstream is that it introduces a bunch of
> clashing names, e.g. state, and member functions that are ios
> analogies for member functions of my base class with different
> names, e.g. good(), bad(), setstate(), etc... The name
> clashes would force me to change names in the base class which
> will in turn effect my context class which has nothing to do
> with ostrstream. These extra functions will make the
> interface of Dbconn confusing. Also, since many of the member
> functions in ostrstream are not virtual I worry that even if I
> override them they will get called by accident if the object
> is ever referenced through a pointer to ostrstream.

If you prefer deriving from ostrstream and want to avoid name
clashes, you could use private derivation. But then again you have
to supply wrapper functions like those above.

Hope that helps!
Bernd


--
+----------------------------------+
| Bernd Eggink |
| Rechenzentrum Uni Hamburg |
| ad...@rzaix13.rrz.uni-hamburg.de |
+----------------------------------+

ad...@rzaix13.uni-hamburg.de

unread,
Nov 8, 1995, 3:00:00 AM11/8/95
to
Dietmar Kuehl (kuehl@uzwil) wrote:
> Hi,

> The answer to $(Subject) is simple: No! Do not try to derive from
> 'ostrstream', or any other class derived from 'ostream' or 'istream':
> The classes derived from 'ostream' and 'istream' are only present for
> convenience and are intended as leaf-classes in the inheritance tree.

This is not entirely true. There is no reason not to derive from an
i/ostream class, especially if you just add some functionality
and leave the shift operator functions alone. The only real
problem may be the overloading of the shift operator functions.

> If you need output send to another stream, just derive a specialized
> class from 'streambuf' which sends the output to the stream requested.
> It is not that hard and much easier to maintain.

Maybe you misunderstood the original poster. What he needs is exactly the
strstreambuf functionality. There is no reason to invent this class
again. And he needs (at least part of) the ostream functionality; so
why not as well use ostrstream?

Michael Bresnahan

unread,
Nov 9, 1995, 3:00:00 AM11/9/95
to ad...@rzaix13.uni-hamburg.de

ad...@rzaix13.uni-hamburg.de () wrote:

>If you prefer deriving from ostrstream and want to avoid name
>clashes, you could use private derivation. But then again you have
>to supply wrapper functions like those above.

Yeah, such came to my mind after posting, however I ran into a
problem. Both class ios and and my base class define a
operator void*(). The compiler complains that it cannot mesh
(or some other word like that) conversion operator lists. Is
this a compiler or language limitation? Is there any way
around it? Let me explain in more generic terms. Take these
classes:

class Base1 {

operator void*();
};

class Base2 {

operator void*();
};

class Derived : public Base1, public Base2 {

};

The HP compiler will not compile this.

Michael Bresnahan

unread,
Nov 9, 1995, 3:00:00 AM11/9/95
to
ad...@rzaix13.uni-hamburg.de () wrote:

>This is not entirely true. There is no reason not to derive from an
>i/ostream class, especially if you just add some functionality
>and leave the shift operator functions alone. The only real
>problem may be the overloading of the shift operator functions.

Ok, now I'm confused... one person saying one thing, the other
saying the opposite. What are the reasons not to derive from
ostrstream?

>Maybe you misunderstood the original poster. What he needs is exactly the
>strstreambuf functionality. There is no reason to invent this class
>again. And he needs (at least part of) the ostream functionality; so
>why not as well use ostrstream?

Yeah, this is exactly what I thought when Dietmar made his
suggestion.

Could you explain further, Dietmar?

Dietmar Kuehl

unread,
Nov 9, 1995, 3:00:00 AM11/9/95
to
Hi,
(ad...@rzaix13.uni-hamburg.de) wrote:
: I think in your case this might be the best idea. There aren't

: quite zillions of functions, and they don't have to be global.
: To avoid hours of typing, you can use a good old macro:
:
: #define SHL(X) Dbconn &operator<<(X x) { str << x; return *this; }
:
: class Dbconn
: {
: public:
: SHL(int)
: SHL(char *)
: // ...
:
: private:
: ostrstream str;
: // ...
: };
:
: Insert as many operator<<() functions (that is, SHL macros) as
: you need, or look them up in your <iostream.h> file.
[...]
: If you prefer deriving from ostrstream and want to avoid name

: clashes, you could use private derivation. But then again you have
: to supply wrapper functions like those above.

Can you give me one single argument why this would be a good idea? What
advantage do I get from deriving from 'ostrstream' instead of deriving
from 'streambuf'? Just rhetorical questions, since I really believe
that the answer will "none". You gain disadvantages with this
approach.

Dietmar Kuehl

unread,
Nov 9, 1995, 3:00:00 AM11/9/95
to
Hi,
(ad...@rzaix13.uni-hamburg.de) wrote:
: Maybe you misunderstood the original poster. What he needs is exactly the

: strstreambuf functionality. There is no reason to invent this class
: again. And he needs (at least part of) the ostream functionality; so
: why not as well use ostrstream?

What he REALLY needs are the shift operators! Look at his example. The
gain of 'ostrstream' is, that it is the only class in current
implementations which catches the bytes send to it and makes them
directly available to the program. As far as I understood the problem,
the original poster wants to do two very simple things:

- assemble a database query using the shift operators
- read the result provided from the database using the shift operators

Both operations work on a database connection to provide this
functionality. Well, nothing as easy as to do as this (without writing
an potentially infinit amount of inserter/extractor functions: remember
that there will be inserter/extactor functions for user defined classes
too!): derive from 'streambuf'.

Derivation from 'streambuf' is not as hard as it sounds. In this case
we need to synchronize a stream used for output (the request) with a
stream used for input (the result). Thus it is natural to use an
'ostream' and an 'istream' which are both using something like a
'dbbuf'. Here is an example on how to set up such a structure:

dbbuf dbconn(/*arguments need to connect to the db */);
ostream dbrequest(&dbconn);
istream dbresult(&dbconn);

dbrequest << "Select * from " << from_string << endl;
dbresult >> row;

Using multiple inheritance, a specialized class can be derived from
'istream' and 'ostream' which combines the 'dbrequest' with the
'dbresult' stream which may result in a more convenient usage, e.g.

dbconn dbstream(/*arguments need to connect to the db */);

dbstream << "Select * from " << from_string << endl;
dbstream >> row;

However, the overall structure is not changed by this modified
approach: 'dbconn' is just present for convenience. It provides only
constructor arguments to its baseclasses and maybe some additional
functionality in its destructor.

Now for the interesting part: The 'dbbuf' which is present in either
approach. Writing to a 'dbbuf' means submitting a data base query.
Reading from a 'dbbuf' means retrieving this result. Thus the
assembled query can be send immediately before reading the result. To
provide further control, a 'sync()' operation should trigger sending
the query which is stored so far. Here is a simple implementation of a
'dbbuf'. It uses an object of class 'string' to actually store the
query (I don't want to bother with growing and shrinking the string in
this simple implementation):

const int buf_size = 1024;

class dbbuf
{
private:
dbase_conn *dbase; // the actual database abstration
string query; // a pointer: will be created when needed
char outbuf[buf_size];
char *inbuf; // returned from 'dbase->retrieve()'

protected:
int send_query(); // send a query to the database
void read_result(); // get the result from the database

int overflow(int); // called if 'outbuf' is full
int underflow(); // called if 'inbuf' is empty (peeking)
int uflow(); // called if 'inbuf' is empty (consuming)
int sync(); // "synchronize external and interal representation"

public:
dbbuf(dbase_conn *);
~dbbuf();
};

Declaration and implementation of streams derived from 'istream' and
'ostream' left out: It's trivial.

The class 'dbase_conn' is expected to provide the following functions:
int dbase_conn::send_query(char const *)
char *dbase_conn::read_result()
void dbase_conn::release_result(char *)

Of course, it is possible to put this class into the implementation of
'dbbuf'. This is not done here to keep the code simple. The constructor
of 'dbbuf' has just to setup the members:

dbbuf::dbbuf(dbase_conn *dbc):
streambuf(),
dbase(dbc), // ownership for 'dbc' is NOT claimed
inbuf(0)
{
setp(outbuf, outbuf + buf_size); // set up the buffer for the query
setg(0, 0, 0); // no result yet
}
~dbbuf()
{
dbase->release_result(inbuf);
}

If the query is really long, it will overflow the buffer before it is
to be submitted. Hence some room has to be made available in the
buffer. The character which didn't fit into the put area will be put
at the beginning of the put area:

int dbbuf::overflow(int c)
{
if (c != EOF)
{
query.append(outbuf, buf_size);
*outbuf = c; // it should hold: 'buf_size > 0'
setp(outbuf + 1, outbuf + buf_size);
}
return 0;
}

If either 'uflow()', 'underflow()', or 'sync()' is called, a query is
send to the database. Here is the simple code:

int dbbuf::send_query()
{
query.append(outbuf, pptr() - outbuf);
return dbase->send_query(query.data());
}

int dbbuf::sync()
{
return send_query();
}

'uflow()' and 'underflow()' are both called, if the input is consumed.
The difference is that 'underflow()' just "peeks" at the next character
while 'uflow()' "consumes the next character. Here are the
implementations using the function 'read_result()' to factor out common
implementation:

void dbbuf::read_result()
{
if (inbuf)
dbase->release_result(inbuf);
inbuf = read_result();
setg(inbuf, inbuf, inbuf + strlen(inbuf));
}
int underflow()
{
read_result();
return sgetc();
}
int uflow()
{
read_result();
return sbumpc();
}

OK. This should be a complete, although not necessarily full-fledged
implementation of a class interfacing the database connection
(encapsuleted in 'dbase_conn') to the iostreams library. Note, however,
that the above code is not tested: it is not even compiled.

Using this approach there is no need to implement gazillions of

Anil Vijendran

unread,
Nov 10, 1995, 3:00:00 AM11/10/95
to
I think the right approach is to derive from streambuf and pass an
instance of the derived streambuf (probably called dbconnection_buf)
to the istream/ostream constructor.

That way you don't need to have those umpteen operator<<'s.
--
Peace.... +<:-)

Anil

Bernd Eggink

unread,
Nov 10, 1995, 3:00:00 AM11/10/95
to
Michael Bresnahan (mbres...@mmm.com) wrote:

> ad...@rzaix13.uni-hamburg.de () wrote:

> >If you prefer deriving from ostrstream and want to avoid name
> >clashes, you could use private derivation. But then again you have
> >to supply wrapper functions like those above.

> Yeah, such came to my mind after posting, however I ran into a

> problem. Both class ios and and my base class define a
> operator void*(). The compiler complains that it cannot mesh
> (or some other word like that) conversion operator lists. Is
> this a compiler or language limitation? Is there any way
> around it? Let me explain in more generic terms. Take these
> classes:

> class Base1 {

> operator void*();
> };

> class Base2 {

> operator void*();
> };

> class Derived : public Base1, public Base2 {

> };

> The HP compiler will not compile this.

Yes, it's ambiguos. You'll have no such problems if you use an ostrstream
member:

class X // (your class, forgot the name...)
{
public:
X &operator<<(char *x) { ostr << x; return *this; }
// other operator functions you need...

void execute()
{
ostr << ends;
char *txt = ostr.str();
interpret(txt);
delete [] txt;
}

private:
ostrstream ostr;
// ..
};

Regards,

Dietmar Kuehl

unread,
Nov 11, 1995, 3:00:00 AM11/11/95
to
Bernd Eggink (ad...@rzaix13.uni-hamburg.de) wrote:
: Dietmar Kuehl (kuehl@uzwil) wrote:
: > Hi,

: > (ad...@rzaix13.uni-hamburg.de) wrote:
: > : Maybe you misunderstood the original poster. What he needs is exactly the
: > : strstreambuf functionality. There is no reason to invent this class
: > : again. And he needs (at least part of) the ostream functionality; so
: > : why not as well use ostrstream?
:
: > What he REALLY needs are the shift operators! Look at his example. The
: > gain of 'ostrstream' is, that it is the only class in current
: > implementations which catches the bytes send to it and makes them
: > directly available to the program. As far as I understood the problem,
: > the original poster wants to do two very simple things:
:
: > - assemble a database query using the shift operators
: > - read the result provided from the database using the shift operators
:
: Maybe you can read thoughts; I can't. From the posters first article,

There is no need to "read" thoughts. Mike just described what he wants
to do: have the behavior of ostrstream to assemble a database query
i.e. to construct a query using inserter functions. Maybe you are right
that he doesn't state this in his first article: I think I saw only his
second article (which didn't provide enough context anyway). However,
deriving from 'ostrstream' or any other class already derived from
'ostream' (or 'istream') is definitely a bad idea in general: These
classes are ONLY present for convenient construction of a stream using
a certain 'streambuf' e.g. 'ostrstream' is a shorthand for

strstreambuf sbuf;
ostream sout(&sbuf);

BTW, there is an additional reason NOT to derive especially from
'ostrstream': It is "deprecated" according to the DWP (i.e. it will
become deprecated as soon if Standard C++ jumps into existance). If you
REALLY want to derive from some stream writing into a string you should
at least (if at all) use 'ostringstream'.

: I can only see that he wants his class to behave like an ostrstream.

Maybe we have different views of comp.lang.c++: I treat questions like
I think would treat a question of a customer asking me for some
advice. The first thing to do is to figure out the real intent of the
customer from some vague description of the problem. Typically, the
description is cluttered with approaches to solve this problem (I
haven't worked as a consultant but this is the experience with some
projects financed by third parties, i.e. not the university). To figure
out the intent you have to take away everything which is part of the
solution. If you have something which might be the problem you can go
ahead and find a solution. It is nice if you can verify that the
problem you have identified is indeed tbe problem of the customer.
Unfortunately, this is typically not possible with this newsgroup...

: Apparently there is a reason for it: He already has a function
: 'execute' which interprets a string as a database query. He didn't
: say a word about reading the result from the database. If he really

He did so in at least one of his articles in this thread. You are right
in assuming that I took all three articles into account, as soon as I
had them available. I didn't take private communication with the poster
into account which I had only after posting a complete solution anyway:
I just asked him to clarify his intent.

: means what you said, deriving from streambuf is clearly the right
: thing. If he just means what he said, notice that my approach is
: MUCH shorter than yours. There are at maximum 20 shift operator
: functions to write (in fact, I think he'll need less than 10),
: and by using a macro this can be done in about 1 minute.

Note, that the size of the implementation does not account for good
design. The difference can only be a few lines: My approach takes only
a few lines, maybe your approach takes even fewer. However, in this
scale size of implementation isn't really an issue!

: > Derivation from 'streambuf' is not as hard as it sounds.
:
: I know that (I wrote a book about it), but it surely isn't the solution
: for _all_ problems.

There are two different pathes to extend the IOstreams library:
- creating additional "external representations"
- creating inserters/extractors for additional types/classes
The implementation of IOstreams is separated into two hierachies to
make it possible having different external representations without the
need to modify existing inserter or extractor functions. What you are
suggesting is to create an additional "external representation" by
modifying existing inserter functions!

PS: Does your book provide new insights or is it a translation of
Teale's book into german as the title suggests? If it is the latter, is
it updated to conform to the upcoming standard as described in the DWP?
Just being curious to determine whether it is a good idea to get the
book for the local library (we already have Teale's book...).

Bernd Eggink

unread,
Nov 11, 1995, 3:00:00 AM11/11/95
to
Dietmar Kuehl (kuehl@uzwil) wrote:
> Hi,
> (ad...@rzaix13.uni-hamburg.de) wrote:
> : Maybe you misunderstood the original poster. What he needs is exactly the
> : strstreambuf functionality. There is no reason to invent this class
> : again. And he needs (at least part of) the ostream functionality; so
> : why not as well use ostrstream?

> What he REALLY needs are the shift operators! Look at his example. The
> gain of 'ostrstream' is, that it is the only class in current
> implementations which catches the bytes send to it and makes them
> directly available to the program. As far as I understood the problem,
> the original poster wants to do two very simple things:

> - assemble a database query using the shift operators
> - read the result provided from the database using the shift operators

Maybe you can read thoughts; I can't. From the posters first article,


I can only see that he wants his class to behave like an ostrstream.

Apparently there is a reason for it: He already has a function
'execute' which interprets a string as a database query. He didn't
say a word about reading the result from the database. If he really

means what you said, deriving from streambuf is clearly the right
thing. If he just means what he said, notice that my approach is
MUCH shorter than yours. There are at maximum 20 shift operator
functions to write (in fact, I think he'll need less than 10),
and by using a macro this can be done in about 1 minute.

[ ... ]

> Derivation from 'streambuf' is not as hard as it sounds.

I know that (I wrote a book about it), but it surely isn't the solution
for _all_ problems.

Regards,

Jerry Coffin

unread,
Nov 13, 1995, 3:00:00 AM11/13/95
to
ad...@rzaix13.uni-hamburg.de (Bernd Eggink) wrote:

[ ... ]

>> the original poster wants to do two very simple things:

>> - assemble a database query using the shift operators
>> - read the result provided from the database using the shift operators

>Maybe you can read thoughts; I can't. From the posters first article,


>I can only see that he wants his class to behave like an ostrstream.
>Apparently there is a reason for it: He already has a function
>'execute' which interprets a string as a database query. He didn't
>say a word about reading the result from the database. If he really
>means what you said, deriving from streambuf is clearly the right
>thing. If he just means what he said, notice that my approach is
>MUCH shorter than yours. There are at maximum 20 shift operator
>functions to write (in fact, I think he'll need less than 10),
>and by using a macro this can be done in about 1 minute.

If size of implementation enters into the question, I think simply
implementing this as a manipulator for ostrstream would be by far the
shortest code:

ostrstream &execute(ostrstream &s)
{
do_execute(s.str());
s.rdbuf()->freeze(0);
return s;
}

ostrstream &operator<<(ostrstream &s,ostrstream &(*m)(ostrstream &s))
{
return m(s);
}

used something like:

ostrstream x;
// Please forgive me if my SQL is wrong...
x << "select " << fields << "from " << database << execute;

I'm not sure I'd consider this _better_ than deriving a new class, but
I'm quite certain it's shorter than any derivation based approach can
hope to be. I guess I'd consider it an open question whether derivation
provided any advantages to justify the extra work.
Later,
Jerry.

/* I can barely express my own opinions; I certainly can't
* express anybody else's.
*
* The universe is a figment of its own imagination.
*/


Bernd Eggink

unread,
Nov 13, 1995, 3:00:00 AM11/13/95
to
Jerry Coffin (jco...@rmii.com) wrote:

> If size of implementation enters into the question, I think simply
> implementing this as a manipulator for ostrstream would be by far the
> shortest code:

> ostrstream &execute(ostrstream &s)
> {
> do_execute(s.str());
> s.rdbuf()->freeze(0);
> return s;
> }

> ostrstream &operator<<(ostrstream &s,ostrstream &(*m)(ostrstream &s))
> {
> return m(s);
> }

> used something like:

> ostrstream x;
> // Please forgive me if my SQL is wrong...
> x << "select " << fields << "from " << database << execute;

> I'm not sure I'd consider this _better_ than deriving a new class, but
> I'm quite certain it's shorter than any derivation based approach can
> hope to be. I guess I'd consider it an open question whether derivation
> provided any advantages to justify the extra work.
> Later,
> Jerry.

Yes, this is quite a good idea, except that it won't work. Remember that
each operator<<() returns a reference to ostream, not to ostrstream.
So you have to put it like this:

ostream &execute(ostream &s)
{
do_execute(((ostrstream &)s).str());
((ostrstream &)s).rdbuf()->freeze(0);
return s;
}

This works, but is dangerous because of the cast into a derivated
class. If your compiler supports the new casts, you could write

do_execute(dynamic_cast<ostrstream &>(s).str());

(and you have to catch the exception that might be thrown).
If not, you can use xalloc to connect some kind of type information
with the stream object. Anyway, I agree that in this case using
a manipulator may be a better idea than deriving.

James Kanze US/ESC 60/3/141 #40763

unread,
Nov 13, 1995, 3:00:00 AM11/13/95
to
In article <4828gq$h...@eurybia.rz.uni-konstanz.de> kuehl@uzwil
(Dietmar Kuehl) writes:

|> Maybe we have different views of comp.lang.c++: I treat questions like
|> I think would treat a question of a customer asking me for some
|> advice. The first thing to do is to figure out the real intent of the
|> customer from some vague description of the problem.

The first thing I do when approched by a customer is to learn
something about his application domain. If I tried to do this with
questions in comp.lang.c++, I wouldn't have time to answer very many
questions, and the responses would be much slower in appearing. (On
the other hand, I'd be reasonably certain that they were right, and on
target, rather than just guessing. Customers pay, and so have a
guarantee of quality.)

|> Typically, the
|> description is cluttered with approaches to solve this problem (I
|> haven't worked as a consultant but this is the experience with some
|> projects financed by third parties, i.e. not the university). To figure
|> out the intent you have to take away everything which is part of the
|> solution. If you have something which might be the problem you can go
|> ahead and find a solution. It is nice if you can verify that the
|> problem you have identified is indeed tbe problem of the customer.
|> Unfortunately, this is typically not possible with this newsgroup...

Since I'm not responding to a customer :-)...

All I know about the original request is from your response, and the
posting you were responding to, but... IMHO, a data base is not a
stream, and using operator>> is *not* an appropriate way to access it.
The model doesn't fit.

I think that deriving from ostrstream (or ostringstream, according to
what's available), and adding a single function, execute, would work.
On the other hand, from a design point of view, it seems to be
combining two distinct functionalities in one class: that of building
up a data base command, and that of partially managing the data base.
(Partially, since there are certainly other things relevant to
databases than just executing the command.)

My own solution would probably be to have a DataBase class with member
functions:

ResultType
DataBase::execute( char const* cmd , ??? )
{
// The real work
}

ResultType
DataBase::execute( ostream const& userCmd , ??? )
{
ostream& cmd = const_cast< ostream& >( userCmd ) ;
ResultType result ;
if ( (ostrstream* str = dynamic_cast< ostrstream* >( &cmd ) ) )
{
(*str) << ends ;
result = execute( str->str() , ??? ) ;
str->freeze( 0 ) ;
}
else if ( (ostringstream* str
= dynamic_cast< ostringstream* >( &cmd ) ) )
result = execute( str->str().c_str() , ??? ) ;
else
result = execute( ostrstream() << cmd.rdbuf() , ??? ) ;
return result ;
}

This allows passing an arbitrary stream as a command. Typically,
however:

db.execute( "Checkpoint" ) ;
db.execute( ostrstream() << "Select * in " << someParam ) ;
// etc.

To tell the truth, this example is just full of code that I don't
normally approve of: casting away const, embedded assignments,
implicit test of pointer (rather than comparing to NULL). I don't
like it one little bit, but I don't know of any other way of obtaining
the same effect (and I prefer local ugliness to bad design).
--
James Kanze Tel.: (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, études et réalisations en logiciel orienté objet --
-- A la recherche d'une activité dans une region francophone


Michael Bresnahan

unread,
Nov 14, 1995, 3:00:00 AM11/14/95
to
ka...@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
wrote:

>All I know about the original request is from your response, and the
>posting you were responding to, but... IMHO, a data base is not a
>stream, and using operator>> is *not* an appropriate way to access it.
>The model doesn't fit.

That is the conclusion I have already come to. I have
foregone the idea of using a ostream class in my
implementation. Instead, I leave it up to the user to build
the SQL command.

Thanks for all the responses.

Jerry Coffin

unread,
Nov 14, 1995, 3:00:00 AM11/14/95
to
ad...@rzaix13.uni-hamburg.de (Bernd Eggink) wrote:

>Jerry Coffin (jco...@rmii.com) wrote:

>> If size of implementation enters into the question, I think simply
>> implementing this as a manipulator for ostrstream would be by far the
>> shortest code:

>> ostrstream &execute(ostrstream &s)
>> {
>> do_execute(s.str());
>> s.rdbuf()->freeze(0);
>> return s;
>> }

>> ostrstream &operator<<(ostrstream &s,ostrstream &(*m)(ostrstream &s))
>> {
>> return m(s);
>> }

[ ... ]

>Yes, this is quite a good idea, except that it won't work. Remember that
>each operator<<() returns a reference to ostream, not to ostrstream.
>So you have to put it like this:

> ostream &execute(ostream &s)
> {
> do_execute(((ostrstream &)s).str());
> ((ostrstream &)s).rdbuf()->freeze(0);
> return s;
> }

But the code above includes an overload of operator<< that receives and
returns the correct types, thus sidestepping this issue entirely.
AFAIK, this should be legal unless there's an existing overload of
operator<< that receives the same argument types, which I can't find and
can only barely imagine. I'd guess that if it did exist, it would be
equivalant to the code above - given that we're receiving a pointer to a
function with a manipulator type signature, I can't think of a whole lot
to do with it except invoke it as a manipulator.

>This works, but is dangerous because of the cast into a derivated
>class. If your compiler supports the new casts, you could write

> do_execute(dynamic_cast<ostrstream &>(s).str());

>(and you have to catch the exception that might be thrown).
>If not, you can use xalloc to connect some kind of type information
>with the stream object. Anyway, I agree that in this case using
>a manipulator may be a better idea than deriving.

Yes - if you try to make the existing overloads for manipulators work
with ostrstreams, it's going to be a great deal of extra work. However,
unless I'm missing something obvious, adding our own overload for
manipulators should avoid the problem entirely.

Steve Willer

unread,
Nov 16, 1995, 3:00:00 AM11/16/95
to
ad...@rzaix13.uni-hamburg.de (Bernd Eggink) wrote:

>Not quite: You forgot ostrstream::str() and, in some implementations,
>ostrstream::freeze().

This reminds me of something that's been bothering me. Does anyone
know the rationale for causing str() to freeze() the stream? Using
this setup, there is no way to simply say

ostrstream ostr;
ostr << "Hi " << "there.";
MessageBox(ostr.str());

and leave it at that? After the str() call, you can't modify the ostr
anymore and you have to deallocate it yourself?? I just don't get it.

To be able to do the things I want to do with a minimum of effort and
unnecessary code, I ended up writing a function:

const char* streambuf(const ostrstream& _stream) {
ostrstream &mystream = const_cast<ostrstream&>(_stream);
mystream << ends;
char *pch = mystream.str();
mystream.rdbuf()->freeze(0);
return pch;
}

Now, I would call MessageBox(streambuf(ostr)) in the above code.

I just don't get why ostrstream::str() can't return a _const char*_
and not call freeze().


Steve Clamage

unread,
Nov 17, 1995, 3:00:00 AM11/17/95
to
In article 12...@sq.com, wil...@carolian.com (Steve Willer) writes:

>ad...@rzaix13.uni-hamburg.de (Bernd Eggink) wrote:
>
>This reminds me of something that's been bothering me. Does anyone
>know the rationale for causing str() to freeze() the stream?

Yes. It avoids the problem of a dangling pointer. Consider this:

ostrm << stuff;
char* p = ostrm.str();
ostrm << more << stuff;
foo(p); // OK ???

Or this:
char* func()
{
ostrstream o; // auto variable
o << stuff;
return o.str();
// is the buffer deleted when o is destroyed?
}

When you add to an ostrstream, the buffer may need to be moved in order
to expand it. You can't in general know when this will happen. In the
second example, the stream library can't know that an active pointer to
the buffer exists when the steam is destroyed. There are essentially two
design choices here.
1. The user has to ensure somehow the buffer won't move or be deleted
as long as any pointer to it anywhere is in use.
2. The library ensures the buffer is frozen when its address is exported.

Number 1 is very error-prone, and iostreams are intended to be safe. In
particular, the exporting of the pointer and the adding to the ostrstream
can occur in widely separated places, and the addition might occur in a
place where the stream is not even known to be an ostrstream. If "o" in
the second example is passed by reference to another function, "func" would
have no way of knowing whether that other function called str(), and if so,
whether the returned address was still in use.

Number 2 retains safety. You can always attempt to write to an ostrstream,
as to any ostream. If it is full, the attempted writes are ignored,
without causing any damage.

You can notify the stream that it is safe to extend the buffer (and delete it
at destruction time) by calling freeze(0). Presumably you do so only when
you know that no pointers are active.

That said, ostrstreams are cumbersome to use, because of all these problems
related to exported dynamic char arrays. The C++ draft standard has a
replacement for strstreams: stringstreams. Instead of a char array for a
buffer, it uses a string class as the buffer. The string class automatically
manages its own storage, so you can safely pass around a string without
worrying about whether it will result in a memory leak or dangling pointer.

---
Steve Clamage, stephen...@eng.sun.com

J. Kanze

unread,
Nov 17, 1995, 3:00:00 AM11/17/95
to
Steve Willer (wil...@carolian.com) wrote:
|> ad...@rzaix13.uni-hamburg.de (Bernd Eggink) wrote:

|> >Not quite: You forgot ostrstream::str() and, in some implementations,
|> >ostrstream::freeze().

|> This reminds me of something that's been bothering me. Does anyone


|> know the rationale for causing str() to freeze() the stream?

|> Using


|> this setup, there is no way to simply say

|> ostrstream ostr;
|> ostr << "Hi " << "there.";
|> MessageBox(ostr.str());

|> and leave it at that? After the str() call, you can't modify the ostr
|> anymore and you have to deallocate it yourself?? I just don't get it.

|> To be able to do the things I want to do with a minimum of effort and
|> unnecessary code, I ended up writing a function:

|> const char* streambuf(const ostrstream& _stream) {
|> ostrstream &mystream = const_cast<ostrstream&>(_stream);
|> mystream << ends;
|> char *pch = mystream.str();
|> mystream.rdbuf()->freeze(0);
|> return pch;
|> }

|> Now, I would call MessageBox(streambuf(ostr)) in the above code.

|> I just don't get why ostrstream::str() can't return a _const char*_
|> and not call freeze().

Safety. If it did so, you end up with too great a risk of a dangling
pointer. In fact, your above routine can easily be modified to show why
you have a problem. Suppose instead of being a parameter, the
ostrstream were a local variable. Without the freeze, the pointer you
would be returning would dangle, since the memory it pointed to in
ostrstream would be deleted on leaving the function.
--
James Kanze (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France

Barry B Floyd

unread,
Nov 17, 1995, 3:00:00 AM11/17/95
to
In article <48i4q9$1...@hardcopy.ny.jpmorgan.com>, Constantine Spathis <ir00...@interramp.com> writes:

|> wil...@carolian.com (Steve Willer) wrote:
|> >ad...@rzaix13.uni-hamburg.de (Bernd Eggink) wrote:
|> >

... stuff deleted

|> >const char* streambuf(const ostrstream& _stream) {
|> > ostrstream &mystream = const_cast<ostrstream&>(_stream);
|> > mystream << ends;
|> > char *pch = mystream.str();
|> > mystream.rdbuf()->freeze(0);
|> > return pch;
|> >}
|> >
|> >Now, I would call MessageBox(streambuf(ostr)) in the above code.
|> >
|> >I just don't get why ostrstream::str() can't return a _const char*_
|> >and not call freeze().
|>

|> I agree so much its ridiculous, not that that has kept me from using
|> streams but it is a major annoyance!
|>
|> -Constantine Spathis
|> Software Lumberjack
|>
|>

In the thread:

Re: HELP: delete strstream object

I posted questions pertaining to str() and freeze(). It is my
understanding that str() calls freeze(), thus freezing further
changes to the underlying streambuf. Since I don't need to add
to the streambuf once I get the str(), this hasn't been on my
mind. However, if I wanted to get a snap shot of the streambuf
(with str()) then continue where I left off, could I simply
follow the call to str() with a call to freeze(0):

ostrstream my_stream ;

my_stream << stream_of_stuff... << ends ;
strcpy ( test_string, my_stream.str() ) ;
my_stream.freeze(0) ;

my_stream << stream_of_more_stuff... << ends ;
strcpy ( test_string, my_stream.str() ) ;
my_stream.freeze(0) ;

...

In the above code, does the 'ends' stay in the streambuf or is it
overwritten/ignored with the unfreeze?

With the streambuf frozen after a call to str(), would the streambuf
be automatically deleted once my_stream goes out of scope?

thanks

barry

--
+--------------------------------------------------------------------+
| Barry B. Floyd \\\ flo...@rpi.edu |
| RPI Alum. '84 '87 '88 \\\ |
+--------------------------------------------------------------------+

Reply all
Reply to author
Forward
0 new messages