There's nothing in the specification for stream buffers that says if you copy a stream buffer this way then the copy will continue to read/write from the same device, nor is cout
specified such that its result from rdbuf()
will behave as you desire.
streambuf is essentially an interface, and its copy constructor does not somehow virtually invoke the copy constructor of any class implementing the interface. Polymorphic types can't be held, copied, passed, etc. by value. In order to copy a polymorphic type you have to use something like a virtual clone()
member function, and the streambuf
interface does not include any such method.
In order to copy the streambuf used by cout
you would have to access it using its dynamic type, and even then it might not be copiable: For example, it might be that multiple stream buffers accessing the same device would need to coordinate or synchronize in some fashion, and a streambuf implementation may disallow copying so that it can safely avoid having to do that synchronization.
What I'm trying to do is create a stream buffer with all the characteristics of std::cout's stream buffer, but with extra member functions built in (for my use). Would you know how to do that?
What extra characteristics are you trying to add? It may be that implementing streambuf is not the appropriate place to add your functionality.
If you want an implementation of the streambuf interface that forwards to a preexisting streambuf then you can create a streambuf class which holds a streambuf pointer, properly treating it as a pointer to a polymorphic type, and implementing the streambuf interface by forwarding calls to the internal streambuf. This is a really simple implementation:
#include <iostream>
struct copiable_streambuf : std::streambuf {
std::streambuf *buf; // non-owning pointer
copiable_streambuf(std::streambuf *buf) : buf(buf) {}
std::streambuf::int_type overflow(std::streambuf::int_type c) {
buf->sputc(c);
return 0;
}
};
int main()
{
copiable_streambuf buf (std::cout.rdbuf());
std::ostream os(&buf);
os << "Hello, World!\n";
}
Your example code involves replacing the buffer used by cout
. If you do this you should be sure to put the original buffer back before cout
is destroyed at the end of the program, because cout
manages the lifetime of its own stream buffer and when cout
s destructor runs it may require the stream buffer it's holding to be the one it originally created.
// RAII type for managing buffer switches.
struct buffer_switcher {
std::ostream &os;
std::streambuf *old;
buffer_switcher(std::ostream &os, std::streambuf *buf)
: os(os), old(os.rdbuf())
{
os.rdbuf(buf);
}
~buffer_switcher() { os.rdbuf(old); }
};
int main() {
// create our forwarding buffer
copiable_streambuf buf(std::cout.rdbuf());
// set up cout to use our buffer and simultaneously ensure that the buffer will get switched back as required
buffer_switcher _(std::cout, &buf);
std::cout << "Hello";
}