【问题标题】:Is it possible to override std::istream read method?是否可以覆盖 std::istream 读取方法?
【发布时间】:2017-06-01 14:31:11
【问题描述】:

我想使用 std::istream 从只提供 2 种方法的给定类中读取数据:

// Returns a byte from the stream (consuming it)
uint8_t getChar(OwnIOStream stream);
// Makes the passed pointer point to the data in the stream
bool getCharBlockPtr(OwnIOStream stream, uint8_t** buffer, uin32_t maxSize, uint32_t* size);

我首先想到的是继承stream_buf,使用getChar()方法实现underflow方法。但是我想使用 getCharBlockPtr() 来避免数据副本(我假设为每个读取字节调用下溢会降低性能)。问题是我需要提前知道我每次要读取的字节数。这就是为什么我在考虑是否可以覆盖 istream 的读取方法。

使用 boost 不是一种选择。

【问题讨论】:

  • 是否可以在streambuf 实现中使用内部缓冲区并在underflow() 中使用getCharBlockPtr 填充它?
  • 不,我想避免数据副本。我需要直接使用 getCharBlockPtr 提供的缓冲区(即将内容直接放入文件中,无需额外副本)。

标签: c++


【解决方案1】:

从 streambuf 派生是一个完全有效的选择。

除了覆盖underflow 之外,您是否需要做更多(如果有的话)取决于。如果OwnIOStream 已经在缓冲数据,那么您可能会通过这样做获得足够的性能。我会先这样做,然后看看情况如何。

下一个明显的步骤是使用getCharBlockPtrstreambuf 有一个 setg,用于将指针设置为缓冲区的开头、当前位置和结尾。至少如果我正确地解释了事情,你会打电话给getCharBlockPtr 并得到开始和结束。然后调用setg 将开始位置和当前位置设置为开始位置,将结束位置设置为结束位置。从那里,streambuf 应该能够直接从缓冲区读取数据。当它用完时,它会调用underflow,您需要再次获取更多数据。

请注意:OwnIOStream 似乎不支持放回区域,而流通常确实希望支持该放回区域。让它正常工作(尤其是在缓冲区开始时放回一个字符)可能有点不重要,要正确支持。

【讨论】:

  • 在您发表评论后,我可以找到tutorial 来继承streambuf。一旦你实现了一个内部缓冲区,放回区域就可以使用它。
  • 是的,一旦创建了一个缓冲区,就可以使用它。这里的重点是使用现有缓冲区而不是创建另一个缓冲区。通常,当您创建缓冲区时,您会在开始时为回退区域留出一些空间 - 但如果您使用的是没有为回退区域留出空间的现有缓冲区,则可能会更加困难。跨度>
  • OwnIOStream 可能已经在缓冲数据,尽管我无权访问其内部代码。我在这里担心的是,如果我每次使用 OwnIOStream 提供的 getChar 方法调用一个字节时实现下溢读取,那么性能可能会很差。这就是我想改用 getCharBlockPtr 的原因。我发现的问题是我不知道 istream 将请求多少字节,并且我不想制作额外的副本。
【解决方案2】:

一般规则是标准 C++ 库中的大多数类并不意味着派生。这里的例外是 streambuf 类,它旨在成为支持 IO 的 object 和 C++ stream 之间的低级接口。

所以这里的标准方法是构建一个自定义streambuf 调用getChar 或更好的getCharBlockPtr,这将允许缓冲。杰瑞的回答解释了如何做到这一点。

不过看来你这里有特殊要求:

  • 您在更高级别上知道要读取的字节数
  • 您正在进行性能关键操作,并希望尽可能避免缓冲区复制 - 但最后一点应在分析后查看...

然后,要求 C++ 流的全部功能可能不是要走的路。构建一个只实现您需要调用的 istream 的方法的自定义类,并且很少有提取器仍然会在高层提供良好的代码,并且可以在低层提供更优化的代码。

但只有你自己知道:

  • 您的更高级别代码是否需要 C++ 流 - 那么自定义类不是一个选项,您必须使用自定义 streambuf
  • 是否可以直接从调用代码中给streambuf预期的大小作为提示。或多或少:

    class OwnStreamBuf: public std::streambuf {
        ...
        void sizehint(size_t hint) { /* size for next read access */
           this->hint = hint
        }
        int_type underflow() {
            ...
            cr = getCharBlockPtr(stream, buffer, hint, size); /* use hint as maxSize */
            ...
        }
    }
    ...
    OwnStreamBuf buf(...);
    class OwnIStream: public istream ...
    OwnIStream is(buf)
    ...
    buf.sizehint(n)
    is >> special_obj;
    ...
    
  • 您是否只需要少量提取器和自定义类是否会更容易从头开始构建。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多