I am trying to create a custom implementation of a std::stringbuf. On some platforms it works fine, and on others I get unexpected results. Here is my class and a test demonstrating the issue:
#include <iostream>
#include <vector>
#include <sstream>
class CombinedLogger : public std::ostream
{
public:
explicit CombinedLogger() : std::ostream(&buffer), buffer(*this) {}
virtual ~CombinedLogger() = default;
void Add(std::ostream& log)
{
logs.push_back(&log);
}
private:
class CombinedStreamBuffer : public std::stringbuf
{
public:
explicit CombinedStreamBuffer(CombinedLogger &log) : log(log) {}
virtual ~CombinedStreamBuffer() = default;
protected:
virtual int overflow(int c)
{
if (c != traits_type::eof())
{
someCustomBuffer << static_cast<char>(c);
}
return c;
}
virtual int sync()
{
for (auto& l : log.logs)
{
*l << someCustomBuffer.str();
l->flush();
}
someCustomBuffer.str("");
str("");
return 0;
}
private:
CombinedLogger &log;
std::stringstream someCustomBuffer;
} buffer;
std::vector<std::ostream*> logs;
};
int main(int, char*[])
{
CombinedLogger cl;
cl.Add(std::cout);
cl << "This is a test to see if my string gets chopped up" << std::endl;
cl << "Here's another test to see if my string gets chopped up" << std::endl;
cl << "And a third test to see if my string gets chopped up" << std::endl;
return 0;
}
When I compile and run under Windows, I get the output I expect:
This is a test to see if my string gets chopped up
Here's another test to see if my string gets chopped up
And a third test to see if my string gets chopped up
If I compile and run under Ubuntu, the output instead looks like this:
This is a test to see if my string gets chopped up
test to see if my string gets chopped up
t to see if my string gets chopped up
After some debugging and experimenting, I found that the missing characters actually end up in the std::stringbuf's own internal buffer (accessible via str()). If I also override xsputn(), I can be sure everything gets put into my customer buffer. My question is: Why do I have to do this? My understanding is that I shouldn't have to override anything except overflow(), and since I didn't specify any other buffer (via setp()), the std::stringbuf buffer should have size zero and overflow should be called for every character.
The information in this answer helped guide me in creating these classes.
In case it's relevant:
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
[edit]I seem to have stumbled upon a solution: removing the call to str("");
in sync() makes it print the expected output on all tested platforms. My question still stands, however, as I don't understand why this call broke the stringbuf.[/edit]