c++ - 自定义输入流。流缓冲区和下溢方法

标签 c++ io stream streambuf

为了理解输入流的工作原理,我设计了以下两个类:

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

在我更改 underflow 方法的逻辑之前,效果很好。主要目标是将数据保存在不同于用户输入的 c 字符串变量 s 中。为了做一个简单的测试,我将 underflow 方法更改为如下:

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

想法是让方法只返回 + 符号而不是用户输入的字符。 因此,例如,如果输入是 123,我希望 +++ 存储在变量 s 中。 那是行不通的。控制台挂起,就好像它在等待更多输入一样。只有一定数量的按键(或发送 EOF)有帮助。

我在这里错过了什么?


正如@ferosekhanj 所指出的,问题是缺少换行符,underflow 的修改版本没有将其返回给调用者。因此,为了使代码正常工作,必须将其返回。这个版本的方法工作正常。

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

最佳答案

根据我以前的 C++ 经验,流 buf 是流的底层缓冲区。当流需要更多数据时,它会调用下溢。在这个方法中,你应该从你的源代码和 setg 中读取。当流有数据要写回源时,它调用溢出。在这个方法中,你从流中读取,写回你的源和 setp。例如,如果您正在从 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);
}

现在来到你的代码,你添加了

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

流读取一个字符串,直到它看到一个 LF(换行符)。因此,当 LF 字符出现时,您将用“+”覆盖它,因此流将永远等待(对于 LF)。通过添加此检查,您的代码应该按照您的预期进行。如果输入 'abc' 则输出 '+++'

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

希望对你有帮助。

关于c++ - 自定义输入流。流缓冲区和下溢方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39017752/

相关文章:

file - 流文件更改

javascript - 如何处理奇怪组合的 websocket 消息?

c++ - 模板类,导致链接问题的实现代码

c++ - 类之间复杂的循环依赖

c - 从文件接收到数据并需要打印它,但程序没有正确读取数据?

haskell - 在 Haskell 中使用哪个 monad 来聚合执行一系列语句时可能发生的异常?

c# - 如何解析多部分 HttpWebResponse

c++ - 仅蚕食右值引用的部分资源

c++ - 如何使用 ncurses 获取 UTF-8 重音

ruby - 使用 Ruby 读取文件的前一行