【问题标题】:Creating a substreambuf to read from an existing istream创建一个 substreambuf 以从现有 istream 中读取
【发布时间】:2014-04-08 17:54:56
【问题描述】:

我正在尝试创建一个自定义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, "
}

我是streambufs 的新手,我觉得我在这里遗漏了一些明显的东西。任何帮助将不胜感激。

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

【问题讨论】:

    标签: c++ istream streambuf


    【解决方案1】:

    当我第一次看到代码时,我觉得这很奇怪。

    int uflow()
    {
        // ...
        return m_sbuf->snextc();
    }
    

    他为什么返回snextc() 的结果?为uflow() 定义的策略是“返回下一个可用字符并将输入流前进一个字符”。如果snextc() 被调用,输入序列将被推进,然后它会返回下一个字符。结果是至少跳过了 1 个字符。

    正确的调用方法应该是sbumpc(),因为它会缓存下一个字符,推进输入流,然后返回。

    return m_sbuf->sbumpc();
    

    Here is a demo.

    【讨论】:

      猜你喜欢
      • 2017-10-29
      • 2011-02-23
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 2015-04-11
      • 2014-01-05
      • 2013-08-03
      • 2023-03-24
      相关资源
      最近更新 更多