Custom input stream. Stream buffer and underflow method

北战南征 提交于 2020-01-03 21:07:34

问题


To understand how input streams work I designed 2 of the following classes:

#include <iostream>

class my_streambuf: public std::streambuf
{
private:
  std::streambuf* buffer;

  char ch;

protected:

  virtual std::streambuf::int_type underflow()
  {
    std::streambuf::int_type result = buffer->sbumpc();

    if (result != traits_type::eof())
    {
      ch = traits_type::to_char_type(result);

      setg(&ch, &ch, &ch + 1);
    }

    return result;
  }

public:
  my_streambuf(std::streambuf* buffer) : buffer(buffer) {};

  virtual ~my_streambuf() {};
};

class my_istream: public std::istream
{
public:
  my_istream(std::istream& stream) : std::istream(new my_streambuf(stream.rdbuf())) {};

  virtual ~my_istream()
  {
    delete rdbuf();
  }
};

int main()
{
  char s[32];
  my_istream is(std::cin);

  is >> s;
  std::cout << s;
  return 0;
}

Which work fine, until I change the logic of underflow method. The primary goal is to save data in c-string valiable s which differs from user-input. To make a simple test, I changed the underflow method to be the following:

virtual std::streambuf::int_type underflow()
{
  std::streambuf::int_type result = buffer->sbumpc();

  if (result != traits_type::eof())
  {
    result = traits_type::to_int_type('+'); // <-- this was added

    ch = traits_type::to_char_type(result);

    setg(&ch, &ch, &ch + 1);
  }

  return result;
}

With the idea being to make the method return only + symbols instead of user-input chars. So for example if input is 123, I expect +++ to be stored in variable s. And that does not work. Console hangs as if it is waiting more input. Only a certain amount of keypressing (or sending EOF) helps.

What am I missing here?


As was pointed out by @ferosekhanj, the problem was the missing newline, which was not returned by the modified version of underflow to the caller. So in order for the code to work properly it has to be returned. This version of the method works fine.

virtual std::streambuf::int_type underflow()
{
  std::streambuf::int_type result = buffer->sbumpc();

  if ((result != traits_type::eof()) && !traits_type::eq(traits_type::to_char_type(result), '\n'))
  {
     result = traits_type::to_int_type('+');

     ch = traits_type::to_char_type(result);

     setg(&ch, &ch, &ch + 1);
  }

  return result;
}

回答1:


From my old C++ experience a stream buf is the underlying buffer for the stream. When the stream needs more data it calls underflow. Inside this method you are suppose to read from your source and setg. When the stream has data to be written back to the source it calls overflow. Inside this method you read from the stream,write back to your source and setp. For example if you are reading the data from a socket in your streambuf

socketbuf::int_type socketbuf::underflow(){
  int bytesRead = 0;
  try{
    bytesRead = soc->read(inbuffer,BUFFER_SIZE-1,0);
    if( bytesRead <= 0 ){
      return traits_type::eof();
    }
  }catch(IOException ioe){
    cout<<"Unable to read data"<<endl;
    return traits_type::eof();
  }
  setg(inbuffer,inbuffer,inbuffer+bytesRead);
  return traits_type::to_int_type(inbuffer[0]);
}

socketbuf::int_type socketbuf::overflow(socketbuf::int_type c){
  int bytesWritten = 0;
  try{
    if(pptr() - pbase() > 0){
      bytesWritten = soc->write(pbase(),(pptr() - pbase()),0);
      if( bytesWritten <= 0 )  return traits_type::not_eof(c);
    }
  }catch(IOException ioe){
    cout<<"Unable to write data"<<endl;
    return traits_type::eof();
  }
  outbuffer[0] = traits_type::to_char_type(c);
  setp(outbuffer,outbuffer+1,outbuffer+BUFFER_SIZE);
  return traits_type::not_eof(c);
}

Now coming to your code, you added

result = traits_type::to_int_type('+'); // <-- this was added

A stream reads a string until it sees a LF(line feed). So when the LF character come you are over writing that with a '+' so the stream will wait (for LF) forever.By adding this check your code should do what you are expecting. output '+++' if you input 'abc'

if (result != 10)// <-- add this in addition
    result = traits_type::to_int_type('+'); // <-- this was added

Hope it helps you.



来源:https://stackoverflow.com/questions/39017752/custom-input-stream-stream-buffer-and-underflow-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!