我想使用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()方法实现下溢方法。但是我想使用getCharBlockPtr()来避免数据副本(我假设为每个读取字节调用下溢会降低性能)。问题是我需要事先知道每次我想要读取的字节数。这就是为什么我在考虑是否可以覆盖istream的read方法。
使用提升不是一种选择。
答案 0 :(得分:0)
一般规则是标准C ++库中的大多数类都不是要派生的。这里的例外是streambuf
类,它是IO支持的对象和C ++ stream
之间的低级接口。
所以这里的标准方式是构建一个允许缓冲的自定义streambuf
调用getChar
或更好getCharBlockPtr
。杰瑞的回答解释了如何做到这一点。
但看起来你有特殊要求:
然后,要求C ++流的全部功能可能不是可行的方法。构建一个只需要实现你需要调用的istream
方法的自定义类,以及一些提取器,仍然可以在高级别提供一个很好的代码,并且可以在低级别提供更优化的代码。
但你和你才能知道:
是否可以直接从调用代码中将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;
...
您是否只需要少量提取器和自定义类,从头开始构建起来会更简单。
答案 1 :(得分:0)
从streambuf派生是一个非常有效的选择。
是否需要做多(如果有的话),而不是覆盖underflow
。如果OwnIOStream
已经在缓冲数据,那么就可以从中获得足够的性能。我会从那开始,看看情况如何。
下一个明显的步骤是使用getCharBlockPtr
。 streambuf
有一个setg
,用于设置指向缓冲区的开头,当前位置和结尾的指针。至少如果我正确地解释了事情,你会打电话给getCharBlockPtr
并开始和结束。然后,您可以调用setg
将开始和当前位置设置为开头,将结束位置设置为结束。从那里,streambuf 应能够直接从缓冲区读取数据。当它用完时,它会调用underflow
,您需要再次获取更多数据。
一个注意事项:它看起来不像OwnIOStream
支持回退区域,这些流通常会支持。让它正常工作(特别是在缓冲区的开头放回一个字符)可能在某种程度上无法正常支持。