如何实现自定义std::streambuf的seekoff()?

问题描述 投票:0回答:3

我有以下基于例如的实现: 这个问题和答案

struct membuf : std::streambuf
{
  membuf(char* begin, char* end)
  {
    this->setg(begin, begin, end);
  }

protected:
  virtual pos_type seekoff(off_type off,
                           std::ios_base::seekdir dir,
                           std::ios_base::openmode which = std::ios_base::in)
  {
    std::istream::pos_type ret;
    if(dir == std::ios_base::cur)
    {
      this->gbump(off);
    }
    // something is missing here...
  }
};

我想按以下方式在我的方法中使用它:

  char buffer[] = { 0x01, 0x0a };
  membuf sbuf(buffer, buffer + sizeof(buffer));
  std::istream in(&sbuf);

然后致电,例如

tellg()
in
并得到正确的结果。

到目前为止,它几乎是完美的 - 它不会在流结束时停止。

我应该如何升级它才能正常工作?

我的主要动机是模仿

std::ifstream
行为,但在测试中将二进制
char[]
输入到它们中(而不是依赖于二进制文件)。

c++ istream seek streambuf
3个回答
9
投票

接受的答案不适用于搜索方向设置为

std::ios_base::beg
std::ios_base::end
的情况。为了支持这些案例,请通过以下方式扩展实施:

pos_type seekoff(off_type off,
                 std::ios_base::seekdir dir,
                 std::ios_base::openmode which = std::ios_base::in) {
  if (dir == std::ios_base::cur)
    gbump(off);
  else if (dir == std::ios_base::end)
    setg(eback(), egptr() + off, egptr());
  else if (dir == std::ios_base::beg)
    setg(eback(), eback() + off, egptr());
  return gptr() - eback();
}

5
投票

看来我错过了当前位置的回报。所以

seekoff
的最终实现如下:

  pos_type seekoff(off_type off,
                   std::ios_base::seekdir dir,
                   std::ios_base::openmode which = std::ios_base::in)
  {
    if (dir == std::ios_base::cur) gbump(off);

    return gptr() - eback();
  }

0
投票

至少对于 GCC 来说,如果

seekg
超过结束指针,你会遇到严重崩溃,例如:

file.seekg(10, std::ios::end);

为了防止崩溃,您需要信号超出绑定错误:

    virtual  std::streambuf::pos_type seekoff(
        std::streambuf::off_type off, std::ios_base::seekdir dir,
        std::ios_base::openmode) override
    {
        auto pos = gptr();
        if (dir == std::ios_base::cur)
            pos += off;
        else if (dir == std::ios_base::end)
            pos = egptr() + off;
        else if (dir == std::ios_base::beg)
            pos = eback() + off;

        //check bunds
        if (pos < eback())
            return std::streambuf::pos_type(-1);
        else if (pos > egptr())
            return std::streambuf::pos_type(-1);

        setg(eback(), pos, egptr());
        return gptr() - eback();
    }
© www.soinside.com 2019 - 2024. All rights reserved.