473,388 Members | 1,298 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

Extend streams in C++

I would like to extend the functionality of all streams in C++ so I
can do some fancy stuff like redirecting the streams on the fly.

I don't want to reimplement the whole stream support in C++ and I
would like to keep as much as possible that is already existing.

However, the only thing that my user would like to see is the
following

#include "myiostream.hpp"

int main() {
my::cout << "Hello World" << std::endl;
}

cout will redirect anything from files to sockets and this redirection
will be handled by a runtime system without used intervention.

My first attempt was to extend ostream and istream and reimplement
some of the functions. But clearly it isn't what I'm looking for,
since I have also to reimplement all other functions such as endl().

I think the way to go is to reimplement basic_streambuf and filebuf.

Am I in the right direction or should I start from lower layers
(ios_base) ? Note that I do not want to remove the support for
whatever currently exists.

Thanks

Jan 13 '08 #1
6 2755
On Jan 12, 9:25 pm, Ioannis Papadopoulos
<giannis.papadopou...@gmail.comwrote:
I would like to extend the functionality of all streams in C++ so I
can do some fancy stuff like redirecting the streams on the fly.

I don't want to reimplement the whole stream support in C++ and I
would like to keep as much as possible that is already existing.

However, the only thing that my user would like to see is the
following

#include "myiostream.hpp"

int main() {
my::cout << "Hello World" << std::endl;

}

cout will redirect anything from files to sockets and this redirection
will be handled by a runtime system without used intervention.

My first attempt was to extend ostream and istream and reimplement
some of the functions. But clearly it isn't what I'm looking for,
since I have also to reimplement all other functions such as endl().

I think the way to go is to reimplement basic_streambuf and filebuf.

Am I in the right direction or should I start from lower layers
(ios_base) ? Note that I do not want to remove the support for
whatever currently exists.

Thanks
Perhaps you are looking at the wrong end of the stick.
The problem with the design suggested above is that you'ld have to
define op<< and op>anyways.

Instead of reinventing the wheel, why not provide insertion and
extraction operators for your classes.
You could then stream its contents to standard output, a filestream,
etc, etc. Now imagine its a socket: same basic principle. You could
provide member operators too (make them part of the interface).

This is a silly example but it should give you a few ideas.

#include <iostream>
#include <ostream>
#include <fstream>
#include <string>

template < typename T >
class Concrete
{
T m_t;
public:
Concrete(const T& t) : m_t(t) { }
// member op<<
void operator<<(const T& t)
{
m_t += t;
}
// friend op<<
friend std::ostream&
operator<<(std::ostream& os, const Concrete& c)
{
os << c.m_t;
return os;
}
};

int main()
{
Concrete<std::stringinstance("a short string");
std::cout << instance << std::endl;

std::string sfile("data.txt");
std::ofstream ofs(sfile.c_str());
if(!ofs)
{
std::cout << "failed to open file: ";
std::cout << sfile << std::endl;
return EXIT_FAILURE;
}
instance << " now got longer"; // inject
ofs << instance << std::endl;
}

/*
a short string
*/

/* data.txt
a short string now got longer
*/
Jan 13 '08 #2
On Jan 13, 3:25 am, Ioannis Papadopoulos
<giannis.papadopou...@gmail.comwrote:
I would like to extend the functionality of all streams in C++ so I
can do some fancy stuff like redirecting the streams on the fly.
I don't want to reimplement the whole stream support in C++ and I
would like to keep as much as possible that is already existing.
However, the only thing that my user would like to see is the
following
#include "myiostream.hpp"
int main() {
my::cout << "Hello World" << std::endl;
}
cout will redirect anything from files to sockets and this
redirection will be handled by a runtime system without used
intervention.
My first attempt was to extend ostream and istream and reimplement
some of the functions. But clearly it isn't what I'm looking for,
since I have also to reimplement all other functions such as endl().
I think the way to go is to reimplement basic_streambuf and filebuf.
Am I in the right direction or should I start from lower layers
(ios_base) ?
Definitely not. Iostream's are carefully designed and have very
good separation of concerns. Sourcing and sinking are done in
the streambuf, using the strategy pattern. All you have to do
is arrange for your custom streambuf to replace the one
std::cout is using, something like:

std::cout.rdbuf( &myCustomStreambuf ) ;

From then on, all output to std::cout will be directed to
myCustomStreambuf, rather than to what it was before. (To avoid
any risk of undefined behavior, you should probably save the
original streambuf, and restore it before program termination.)

Whether this is a good idea or not is another question.
Generally, if a programmer outputs to std::cout, he has very
good reasons for doing so, and "redirecting" his output is doing
him a disfavor. Such a trick might be useful, however, if you
have to deal with poorly written legacy code, which uses
std::cout when it should have used an std::ostream& passed in to
it.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jan 13 '08 #3
On Jan 13, 6:58 am, Salt_Peter <pj_h...@yahoo.comwrote:
On Jan 12, 9:25 pm, Ioannis Papadopoulos
[...]
Instead of reinventing the wheel, why not provide insertion and
extraction operators for your classes.
That addresses a different problem, and is a good reason why he
shouldn't try to replace istream and ostream---he'd have to
reimplement all of these insertion and extraction operators as
well. (There are cases where it is reasonable to wrap the
istream or the ostream; in such cases, the wrapper code uses
templates to recover the original << and >operators and use
them.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jan 13 '08 #4
On 13 Ιαν, 04:31, James Kanze <james.ka...@gmail.comwrote:
On Jan 13, 3:25 am, Ioannis Papadopoulos

<giannis.papadopou...@gmail.comwrote:
I would like to extend the functionality of all streams in C++ so I
can do some fancy stuff like redirecting the streams on the fly.
I don't want to reimplement the whole stream support in C++ and I
would like to keep as much as possible that is already existing.
However, the only thing that my user would like to see is the
following
#include "myiostream.hpp"
int main() {
my::cout << "Hello World" << std::endl;
}
cout will redirect anything from files to sockets and this
redirection will be handled by a runtime system without used
intervention.
My first attempt was to extend ostream and istream and reimplement
some of the functions. But clearly it isn't what I'm looking for,
since I have also to reimplement all other functions such as endl().
I think the way to go is to reimplement basic_streambuf and filebuf.
Am I in the right direction or should I start from lower layers
(ios_base) ?

Definitely not. Iostream's are carefully designed and have very
good separation of concerns. Sourcing and sinking are done in
the streambuf, using the strategy pattern. All you have to do
is arrange for your custom streambuf to replace the one
std::cout is using, something like:

std::cout.rdbuf( &myCustomStreambuf ) ;

From then on, all output to std::cout will be directed to
myCustomStreambuf, rather than to what it was before. (To avoid
any risk of undefined behavior, you should probably save the
original streambuf, and restore it before program termination.)

Whether this is a good idea or not is another question.
Generally, if a programmer outputs to std::cout, he has very
good reasons for doing so, and "redirecting" his output is doing
him a disfavor. Such a trick might be useful, however, if you
have to deal with poorly written legacy code, which uses
std::cout when it should have used an std::ostream& passed in to
it.

--
James Kanze (GABI Software) email:james.ka...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 0034
I'm not talking about actually changing where std::cout directs
whatever it's written into it. I want my::cout and this will be
handled by a runtime system. The user should be able to use std::cout
as before and expect the same behavior. However, the behavior of
my::cout will be whatever the runtime wants.

I want to make my::cout as interoperable with current functions and
classes as possible - that is I don't want my user to implement any
new >and << operators for his/her classes.

Jan 14 '08 #5
In article <6de450ee-01bf-4ccf-895b-
b3**********@m77g2000hsc.googlegroups.com>,
gi******************@gmail.com says...

[ ... ]
I'm not talking about actually changing where std::cout directs
whatever it's written into it. I want my::cout and this will be
handled by a runtime system. The user should be able to use std::cout
as before and expect the same behavior. However, the behavior of
my::cout will be whatever the runtime wants.

I want to make my::cout as interoperable with current functions and
classes as possible - that is I don't want my user to implement any
new >and << operators for his/her classes.
You've told us one part of what you want: to allow the user's insertion
and extraction operators to work with your stream object(s).

The only other thing you've said is:
cout will redirect anything from files to sockets and this redirection
will be handled by a runtime system without used intervention.
To make this work, you'll probably have to do what James has advised
against (i.e. create your own stream class) as well as creating your own
socket-based stream buffer class. Making it happen entirely
transparently may be a bit difficult though. When you you write to a
file, you normally only need to supply the name of the file, and then
you can put data into it. Writing to a socket requires a bit more
information: the name/address of the server, the type of protocol to use
(e.g. TCP vs. UDP) and the socket number to write to (and possibly a few
more things specifying such things as timeouts and such).

You _could_ create a buffer object specifying all that, then attach it
to an object of one of the existing stream classes, but if you're using
it much, you probably want a new stream class that allows you to specify
all that and pass it through when it creates the buffer object.

There are quite a few existing samples of how to do this. One that's
relatively small and simple is Socket++, available from:

http://www.cs.utexas.edu/users/laven...rses/socket++/

Another that's well known is ACE, though it's far from small or simple.
Available from:

http://www.cs.wustl.edu/~schmidt/ACE.html

If you want something to download and use as-is, ACE may be a better
choice as it's in current development (whereas Socket++ doesn't seem to
have been touched in years, though that may just be because it's fine
the way it is). If you just want some guidance as to the basics of how
to do the job, Socket++ is probably better due to its smaller size and
relative simplicity.

One last note: I've used things like this a few times, and while they
initially seem like a great idea, they haven't worked out very well in
the long run, at least for me. For building simple clients they aren't
too bad, but for servers (especially) they're pretty close to useless.

The problem is that streams are built around the idea that you decide
when to read or write a stream. A server mostly doesn't have that luxury
-- rather, it waits for a client, and then reacts to the client's
request. That said, some people have built some fairly serious systems
on top of ACE (for one example) so it's clearly workable even though I'm
not sure it's the ideal model for the job. Then again, ACE provides a
LOT of other stuff, and I suspect quite a bit of what's really used is
that other stuff...

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 14 '08 #6
On Jan 14, 7:26 am, Jerry Coffin <jcof...@taeus.comwrote:
In article <6de450ee-01bf-4ccf-895b-
b34c0cebc...@m77g2000hsc.googlegroups.com>,
giannis.papadopou...@gmail.com says...
[ ... ]
I'm not talking about actually changing where std::cout directs
whatever it's written into it. I want my::cout and this will be
handled by a runtime system. The user should be able to use std::cout
as before and expect the same behavior. However, the behavior of
my::cout will be whatever the runtime wants.
I want to make my::cout as interoperable with current functions and
classes as possible - that is I don't want my user to implement any
new >and << operators for his/her classes.
You've told us one part of what you want: to allow the user's insertion
and extraction operators to work with your stream object(s).
The only other thing you've said is:
cout will redirect anything from files to sockets and this redirection
will be handled by a runtime system without used intervention.
To make this work, you'll probably have to do what James has advised
against (i.e. create your own stream class) as well as creating your own
socket-based stream buffer class.
Not at all:

namespace my
{
std::ostream cout( (getDesiredStreambuf()) ) ;
}

About the only reason to create a new ostream class would be to
provide convenience initializers, so that the user can create an
ostream using your streambuf in a single declaration (along the
lines of ofstream).
Making it happen entirely transparently may be a bit difficult
though. When you you write to a file, you normally only need
to supply the name of the file, and then you can put data into
it. Writing to a socket requires a bit more information: the
name/address of the server, the type of protocol to use (e.g.
TCP vs. UDP) and the socket number to write to (and possibly a
few more things specifying such things as timeouts and such).
Actually, it wouldn't be too difficult if an implementation of
filebuf recognizeds URL's. (At one point I experimented with
one which would create a separate process, and read or write to
a pipe connected to the process, if the filename started with a
"!". So you could do things like:
std::ifstream input( "! gunzip < gzippedData.gz" ) ;
. I don't think handling URL's would be much more difficult,
conceptually.)
You _could_ create a buffer object specifying all that, then
attach it to an object of one of the existing stream classes,
but if you're using it much, you probably want a new stream
class that allows you to specify all that and pass it through
when it creates the buffer object.
There are quite a few existing samples of how to do this. One that's
relatively small and simple is Socket++, available from:
http://www.cs.utexas.edu/users/laven...rses/socket++/
Another that's well known is ACE, though it's far from small or simple.
Available from:
http://www.cs.wustl.edu/~schmidt/ACE.html
If you want something to download and use as-is, ACE may be a better
choice as it's in current development (whereas Socket++ doesn't seem to
have been touched in years, though that may just be because it's fine
the way it is). If you just want some guidance as to the basics of how
to do the job, Socket++ is probably better due to its smaller size and
relative simplicity.
One last note: I've used things like this a few times, and while they
initially seem like a great idea, they haven't worked out very well in
the long run, at least for me. For building simple clients they aren't
too bad, but for servers (especially) they're pretty close to useless.
The problem is that streams are built around the idea that you
decide when to read or write a stream. A server mostly doesn't
have that luxury -- rather, it waits for a client, and then
reacts to the client's request.
Typically, the server has two different levels: in the main
thread, it "accepts", with no streams involved. Once it has a
TCP connection, however, the input can often be read as a
stream, at least if each connection is handled in a separate
thread. It input has to be active while processing previous
input (not necessary in a lot of protocols), then you just spawn
another thread for the processing, and you're still OK.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jan 14 '08 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Ronald Legere | last post by:
The new itertools stuff is pretty cool. One thing that bothers me though is that there seems to be no way to copy an iterator. How does one work around this? Is there a trick that I am missing? ...
3
by: Tron Thomas | last post by:
What does binary mode for an ofstream object do anyway? Despite which mode the stream uses, operator << writes numeric value as their ASCII representation. I read on the Internet that it is...
8
by: bonj | last post by:
hello I hope somebody can help me get my head around this area of 'stream' programming... I know that streams are very fashionable nowadays so hopefully there'll be lots of replies. ;-) ...
11
by: Kobu | last post by:
I have a question about C's abstract "streams" (that I can't seem to FULLY understand from reading several tutorials). Streams seems to suggest that input can be treated continously if needed....
2
by: Peter Rilling | last post by:
One nice thing about collections and arrays is that they implement the IEnumerator and IEnumerable interfaces which allow for more then one iterator to walk the list of items without affecting the...
2
by: bonk | last post by:
Hello how do I connect streams in c# ? Imagine the followung scenario: I have a StreamWriter that writes Text to a Stream. How can I tell that Stream to pass that Data to another Stream...
1
by: Chris | last post by:
I'm reading up on streams and I have two articles that seem to conflict with each other. One article describes streams and lists a few of the major ones (FileStream, Memory Stream, Network...
2
by: Abhishek | last post by:
what are the STDUPDATE, STDERR, STDOUT and STDIN streams and how does one access these streams in C language. I am aware of the function fprintf(FILE *fp, char * format, char *s) which puts the...
3
by: jacobstr | last post by:
I've noticed Object.extend used in a few different ways and I'm having trouble distinguishing why certain usages apply to a given situation. On line 804 Ajax.Base is defined as follows: ...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.