我正在尝试创建一个自定义std::streambuf
,它充当父流的子流。这是对this SO thread answer中概述的实施的改编。
在下面的示例中,我试图简单地读取流的前5个字符"Hello,"
。但是,当我将ifstream.read()
调用buffer
时,缓冲区会被"ello, "
填充,就像它被一个人关闭一样。
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream ss;
ss << "Hello, World!";
substreambuf asd(ss.rdbuf(), 0, 5);
istream istream(&asd);
char buffer[6] = { '\0' };
istream.read(buffer, sizeof(buffer));
cout << buffer << endl; //prints "ello, "
}
我是streambuf
的新手,我觉得我在这里遗漏了一些明显的东西。任何帮助将不胜感激。
以下是substreambuf
的定义:
#include <iostream>
#include <sstream>
namespace std
{
struct substreambuf : public streambuf
{
explicit substreambuf(streambuf* sbuf, streampos pos, streampos len) :
m_sbuf(sbuf),
m_pos(pos),
m_len(len),
m_read(0)
{
m_sbuf->pubseekpos(pos);
setbuf(nullptr, 0);
}
protected:
int underflow()
{
if (m_read >= m_len)
{
return traits_type::eof();
}
return m_sbuf->sgetc();
}
int uflow()
{
if (m_read >= m_len)
{
return traits_type::eof();
}
m_read += 1;
return m_sbuf->snextc();
}
streampos seekoff(streamoff off, ios_base::seekdir seekdir, ios_base::openmode openmode = ios_base::in | ios_base::out)
{
if (seekdir == ios_base::beg)
{
off += m_pos;
}
else if (seekdir == ios_base::cur)
{
off += m_pos + m_read;
}
else if (seekdir == ios_base::end)
{
off += m_pos + m_len;
}
return m_sbuf->pubseekpos(off, openmode) - m_pos;
}
streampos seekpos(streampos streampos, ios_base::openmode openmode = ios_base::in | ios_base::out)
{
streampos += m_pos;
if (streampos > m_pos + m_len)
{
return -1;
}
return m_sbuf->pubseekpos(streampos, openmode) - m_pos;
}
private:
streambuf* m_sbuf;
streampos m_pos;
streamsize m_len;
streampos m_read;
};
};
答案 0 :(得分:1)
当我第一次看到代码时,我觉得这很奇怪。
int uflow()
{
// ...
return m_sbuf->snextc();
}
为什么他会返回snextc()
的结果?为uflow()
定义的策略是“返回下一个可用字符并将输入流推进一个字符”。如果调用snextc()
,输入序列将被提前,然后它将返回下一个字符。结果是至少跳过1个字符。
正确的调用方法是 sbumpc()
,因为它会先缓存下一个字符 ,提前输入流,然后返回它。
return m_sbuf->sbumpc();