Search code examples
c++iostream

What's wrong with this stream buffer?


What's wrong with my overflow() here. When I print oss.str() it prints "Hello, Wor" instead of "Hello, World". What did I do wrong?

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

class io_buffer : public std::streambuf
{
public:
    io_buffer(std::ostream& os, int buf_size = 4)
        : os_(os), buffer(buf_size)
    {
        os_.clear();
        char* beg = buffer.data();
        setp(beg, beg + buffer.size());
    }

    int_type overflow(int_type c)
    {
        if (os_ && !traits_type::eq_int_type(c, traits_type::eof()))
        {
            *pptr() = traits_type::to_char_type(c);
            pbump(1);

            if (flush())
            {
                setp(buffer.data(), buffer.data() + buffer.size());
                return c;
            } else
                return traits_type::eof();
        }

        return traits_type::not_eof(c);
    }

    bool flush()
    {
        return os_.write(pbase(), pptr() - pbase());
    }

    int sync()
    {
        return flush() ? 0 : -1;
    }
private:
    std::ostream& os_;
    std::vector<char> buffer;
};

int main()
{
    std::ostringstream oss;
    io_buffer buf(oss);

    std::ostream os(&buf);
    std::string str("Hello, World");

    os << str;
    std::cout << oss.str() << std::endl;
}

Solution

  • You need to flush also a std::vector (buffer), i.e:

    int_type overflow(int_type c)
        {
            if (os_ && !traits_type::eq_int_type(c, traits_type::eof()))
            {
                *pptr() = traits_type::to_char_type(c);
                pbump(1);
    
                if (flush())
                {
                    buffer.clear();  // <-
                    setp(buffer.data(), buffer.data() + buffer.size());
                    return c;
                } else
                    return traits_type::eof();
            }
    
            return traits_type::not_eof(c);
        }
    

    Even better, as 0x499602D2 address suggested use pbump(-buffer.size()) to avoid multiple calls to overflow().

    Watch out for your destructor as it is required to do a flush: