1

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]

Kerry
  • 233
  • 1
  • 8
  • 1
    If you inherit `streambuf`, you only need to override `overflow`, because `streambuf` block-processing functions all call the single versions repeatedly. `stringbuf` can have more efficient block-processing. – Ben Voigt Jan 18 '18 at 21:24
  • @BenVoigt Yes, that's my understanding, but that's not what I observed. – Kerry Jan 19 '18 at 22:05
  • Then would you please you update your question with the results you get when you inherit from `streambuf`? (And no, when James Kanze and I write `streambuf`, that is not a misspelling of `stringbuf`. We are talking about the base class of `stringbuf`.) – Ben Voigt Jan 19 '18 at 22:12
  • @BenVoigt Sorry - I misread `streambuf` as `stringbuf`. In your first comment. When I inherit from `streambuf`, I get a compiler error, since `streambuf` has no member named `str()`. So it does tell me I have to remove the line that's actually causing the issue. This is at least a partial solution. Can you expand on how `stringbuf` handles block-processing? Sounds like that may be the root of the issue. – Kerry Jan 24 '18 at 15:05
  • You don't need to know how `stringbuf` maps block processing onto its virtual functions, you need to stop inheriting from it. `stringbuf` is not designed to be a base class. – Ben Voigt Jan 24 '18 at 15:08

0 Answers0