2

the following code simply tests how often underflow is called when using std::istream read on an std::stringbuf.

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

class TestStringBuf : 
public std::stringbuf
{
public:

    int_type underflow()
    {
        std::cout<<"TestStringBuf underflow"<<std::endl;
        return std::stringbuf::underflow();
    }
};

int main(int argc, const char * argv[])
{
    TestStringBuf buf;
    std::iostream stream(&buf);

    stream << "tesr";

    std::vector<char> data(4);
    stream.read(&data[0], 4);

    for(int i=0; i<data.size(); ++i)
        std::cout<<data[i];
    std::cout<<std::endl;

    return 0;
}

the output is:

TestStringBuf underflow
TestStringBuf underflow
test

I expected underflow to be called only once, since I read exactly the amount of bytes present in the get area, so why should it underflow again? Is this the expected behavior? I am asking because my custom underflow method can potentially block for a long time to read new data, so the second call to underflow is not very desirable in this case.

I am on Osx using clang 3.1 and libc++.

Thank you!

Update:

I just made a completely seperate test and it seems to me that this is a weirdness in the libc++ implementation since this does not happen with libstd++. can someone test this with other implementations? is this a bug or just an implementation difference (feels pretty buggy to me). I updated the code above so you can copy and paste it into any main.cpp.

Update2:

After all it was a bug in libc++, see: http://llvm.org/bugs/show_bug.cgi?id=13113 . If you compile libc++ yourself the bug should be gone, I will try that soon.

moka
  • 4,353
  • 2
  • 37
  • 63
  • Maybe it calls underflow when it goes past position 3 to the end of the stream? –  Jun 14 '12 at 16:57
  • but why should it go past position 3? I would expect it to go past position 3 in a subsequent call to get() or read() and its siblings. – moka Jun 14 '12 at 17:04

1 Answers1

0

The C++ standard explicitly allows the implementation of std::basic_stringbuf to store the character sequence in a std::basic_string instead of using the internal buffer of std::basic_streambuf.

bjhend
  • 1,538
  • 11
  • 25
  • I am not sure how this relates to the question. I only chose stringbuf for the example simplicity. The behavior is identical when inheriting from std::streambuf directly. Could you elaborate what you mean? – moka Jun 14 '12 at 17:22
  • std::streambuf provides an interface for buffered access to a character sequence somewhere else (RAM, file, TCP stream, ...). But the standard doesn't specify how much buffering to use. – bjhend Jun 14 '12 at 18:03
  • yeah I know, i noticed this behavior when working on a custom std::streambuf for tcp sockets. underflow is called too early in libc++ which can cause very long blocks for no reason. – moka Jun 14 '12 at 18:59
  • Maybe it helps to set a bigger buffer with std::streambuf::pubsetbuf. Don't forget to check return value to be non-null and to delete that buffer after the lifetime of the std::streambuf object. I've never tried that, so I don't know if it helps and if it has any more pitfalls. – bjhend Jun 15 '12 at 08:59