自定义输入流。流缓冲区和下溢方法
Custom input stream. Stream buffer and underflow method
为了理解输入流的工作原理,我设计了以下两个 类:
#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;
}
想法是使方法 return 仅 +
符号而不是用户输入的字符。
因此,例如,如果输入是 123
,我希望 +++
存储在变量 s
中。
那是行不通的。控制台挂起,就好像它在等待更多输入一样。只有一定数量的按键(或发送 EOF)有帮助。
我在这里错过了什么?
正如@ferosekhanj 所指出的那样,问题是缺少换行符,return 修改后的 underflow
版本没有向调用者提供换行符。因此,为了使代码正常工作,必须对其进行 returned。这个版本的方法工作正常。
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)forever.By 添加此检查您的代码是否应该按照您的预期进行。如果输入 'abc'
则输出 '+++'
if (result != 10)// <-- add this in addition
result = traits_type::to_int_type('+'); // <-- this was added
希望对您有所帮助。
为了理解输入流的工作原理,我设计了以下两个 类:
#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;
}
想法是使方法 return 仅 +
符号而不是用户输入的字符。
因此,例如,如果输入是 123
,我希望 +++
存储在变量 s
中。
那是行不通的。控制台挂起,就好像它在等待更多输入一样。只有一定数量的按键(或发送 EOF)有帮助。
我在这里错过了什么?
正如@ferosekhanj 所指出的那样,问题是缺少换行符,return 修改后的 underflow
版本没有向调用者提供换行符。因此,为了使代码正常工作,必须对其进行 returned。这个版本的方法工作正常。
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)forever.By 添加此检查您的代码是否应该按照您的预期进行。如果输入 'abc'
则输出 '+++'if (result != 10)// <-- add this in addition
result = traits_type::to_int_type('+'); // <-- this was added
希望对您有所帮助。