uli wrote:
Ok, I tried to figure it out with my STL literature.
STL literature would not cover anything related to streams (with the
exception of the various stream iterators) since streams are not part
of the STL: the STL is a library which essentially became the
functional, algorithms, iterators, and containers library of the
standard C++ library. That is STL != standard C++ library.
But for redirecting it to another function how can I change the streambuf*
to 'string' then, like:
Well, this is not exactly what you probably want to do but you could
use a 'std::stringbuf' at first:
#include <iostream>
#include <sstream>
int main() {
std::streambuf* cout_sbuf = std::cout.rdbuf();
std::stringbuf sbuf;
std::cout.rdbuf(&sbuf);
// ...
printf("stream contents: %s\n", sbuf.str().c_str());
std::cout.rdbuf(cout_sbuf);
}
It is relatively important that you restore the original stream buffer
into the stream because after exiting 'main()' the standard stream
objects may be flushed (due to the behavior of the destructor of
'std::ios_base::Init'). Since the installed stream buffer is destructed
by then, this would result in a crash during program termination which
is generally not the best behavior and may even cause havoc on some of
the data which is not yet flushed.
However, I was actually not refering to installing one of the existing
stream buffers since these don't really do the right thing. You want
to create your own stream buffer by deriving from 'std::streambuf' and
overriding the 'overflow()' and 'sync()' methods. The tricky part in
your particular setup is that you apparently have two routes to write
output:
- you might use 'std::cout' to write output
- you might use the underlying mechanism directly to write output
In situations like this you get synchronization problems if you are
not careful and do buffering in the stream buffer. On the other hand,
using an unbuffered stream buffer is likely to cause a performance
problem. You might compromise on setting the 'unitbuf' flag which will
flush the stream after every insertion operation. Another alternative
is to terminate all uses of 'std::cout' with 'std::endl' or 'std::flush'
(the difference between these two is that the former adds a newline
prior to the flush; in general, I recommend against use of 'std::endl'
because it mixes two entirely separate issues but sometimes it just has
the right semantics...).
A simple stream buffer for your purpose would look something like this:
struct printfbuf: std::streambuf {
enum { s_size = 1024 };
printfbuf() { setp(m_buffer, m_buffer + s_size - 2); }
private:
int_type overflow(int_type c) {
if (!traits_type::eq_int_type(c, traits_type::eof()) {
*pptr() = traits_type::to_char_type(c);
pbump(1);
}
return sync() != -1? traits_type::not_eof(c): traits_type::eof();
}
int sync() {
*pptr() = 0;
printf(pbase());
setp(m_buffer, m_buffer + s_size - 2);
return 0;
}
char m_buffer[s_size];
};
This code is not tested (not even compiled) and I guess I forgot
something important. However, to find out more about implementing
stream buffers, you can have a look at various resources:
- Nicolai Josuttis' book "The C++ Standard Library" (Addison-Wesley)
describes this stuff (actually, I have translated/rewritten this
section)
- Angelika Langer and Klaus Kreft's book "C++ IOStreams and Locales"
(Addison-Wesley) covers this stuff in depth
- I have written loads of articles in newsgroup (use eg.
<http://group.google.com/> to locate past articles)
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting