template boy
template boy

Reputation: 10490

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;
}

Upvotes: 1

Views: 250

Answers (2)

4pie0
4pie0

Reputation: 29754

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:

Upvotes: 1

marcinj
marcinj

Reputation: 50046

The problem is that you use:

setp(beg, beg + buffer.size());

and in overflow() you add new element with no reallocation, the end pointer should be accessible (if you dont want to reallocate), otherwise you need to reallocate your buffer in overflow(). So change it to:

setp(beg, beg + buffer.size() - 1);

in io_buffer constructor

and later in overflow change setp to:

pbump(-(pptr() - pbase()));

also to flush your buffer add endl:

os << str << endl;

working example: http://coliru.stacked-crooked.com/a/7c72ecfe78bb2aee

Upvotes: 1

Related Questions