istream for char buffer

时间:2015-12-09 18:30:10

标签: c++ stl istream

在Qt库中有QByteArray和QDataStream类,它允许我使用非常容易使用的语法读取和写入memmory缓冲区中的变量:

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

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

const char* data = getData();
size_t size = getSize();

membuffer buf( data, data + size );
std::istream str( buf );
double d = 0;
str >> d;

请注意,不应复制数据!

1 个答案:

答案 0 :(得分:0)

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

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

这个简单的流缓冲区只是将流缓冲区“get-area”设置为范围[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)) {
    }
};

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