字符缓冲区的istream

istream for char buffer

本文关键字:istream 缓冲区 字符      更新时间:2023-10-16

在Qt库中有QByteArray和QDataStream类,它们允许我用非常容易使用的语法将变量读写到内存缓冲区:

QByteArray data = getData();
QDataStream stream( data );
double d = 0;
int i = 0;
stream >> d >> i;

如何用stl流类实现simmilar行为?例如,我有一个constchar*数据和它的大小,所以我想构造std::istream并从该数据中读取变量:

const char* data = getData();
size_t size = getSize();
membuffer buf( data, data + size );
std::istream str( buf );
double d = 0;
str >> d;

请注意,不应复制数据!

假设您有一个固定大小的数据缓冲区及其大小,那么通过创建一个合适的流缓冲区来实现它是微不足道的:

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

这个简单的流缓冲区只是将流缓冲区"获取区域"设置为范围[begin, end)begin的使用次数是设置"放回区域"的两次,在这种情况下,放回区域是空的)。当没有更多的字符可读取时,流将尝试调用默认实现指示失败的underflow()。如果你想读取更多的字符,你可以覆盖underflow(),在新设置的缓冲区中提供更多的字符。

有了它,你可以使用这个内存支持的流缓冲区创建一个流:

membuf       sbuf(begin, end);
std::istream in(&sbuf);
double d = 0;
if (in >> d) { // always check conversions from string to a value...
    // ...
}

为了更方便起见,流缓冲区和流的创建也可以绑定到一个类中。有一个小技巧是,流缓冲区应该更早创建,但这是可行的:

class imemstream: private virtual membuf, public std::istream {
public:
    imemstream(char* begin, char* end)
        : membuf(begin, end)
        , std::ios(static_cast<std::streambuf*>(this))
        , std::istream(static_cast<std::streambuf*>(this)) {
    }
};

不过,这只是一个警告:创建流比复制大量数据更昂贵。也就是说,如果你想在循环中使用该流,你可能想提供重置缓冲区的功能(可能与清除状态标志相结合)。