如何从内存缓冲区初始化一个 C++ 的 std::istringstream?

16

我有一个内存块(不透明),我想通过MySQL的C++适配器将其存储在Blob中。适配器期望一个istream:

virtual void setBlob(unsigned int parameterIndex, std::istream * blob) = 0;

我的问题是:如何从这个内存块(类型为char*)创建std::istream流。它不是字符串,因为它没有以空字符结尾(但我当然知道它的长度)。

我找不到一种方法可以在不将内存块复制到std::string中的情况下完成它。我认为这有点浪费。像这样的东西不起作用:

    std::streambuf istringbuf(blockPtr, blockLength);
    std::istringstream tmp_blob(&istringbuf);

因为std::streambuf没有这样的构造函数。我看到了以下建议。

    std:: istringstream       tmp_blob;
    tmp_blob.rdbuf()->pubsetbuf(blockPtr, blockLength);

这是正确的方式吗?


可能是设置标准流使用的内部缓冲区(pubsetbuf)的重复问题。 - Ciro Santilli OurBigBook.com
4个回答

49

实际上,编写一个一次性的std::streambuf相当容易,它可以将缓冲区作为所有虚拟函数的默认行为直接使用,因为std::streambuf的所有虚拟函数都会做正确的事情。您可以在构造函数中使用setg来设置读取区域,而underflowuflow可以安全地返回traits_type::eof(),因为初始获取区域的结尾是流的结尾。

例如:

#include <streambuf>
#include <iostream>
#include <istream>
#include <ostream>

struct OneShotReadBuf : public std::streambuf
{
    OneShotReadBuf(char* s, std::size_t n)
    {
        setg(s, s, s + n);
    }
};

char hw[] = "Hello, World!\n";

int main()
{
    // In this case disregard the null terminator
    OneShotReadBuf osrb(hw, sizeof hw - 1);
    std::istream istr(&osrb);

    istr >> std::cout.rdbuf();
}

哈哈,当我发布我的问题时,你的解决方案没有出现在搜索结果中。我们的东西基本上是一样的 ;) https://dev59.com/bnI95IYBdhLWcg3w8y2N - Marcin Seredynski

9

看看 std::istrstream,它有一个构造函数。

 istrstream( char* pch, int nLength );

这个类已经有点过时了,或者至少你通常会被告知使用其他类。
strstream的问题在于它更复杂地管理char*缓冲区的内存,所以一般情况下,您会更喜欢stringstream,因为它会为您进行内存管理。然而,在这种情况下,您已经在管理char*的内存,因此正常的好处在这种情况下反而是一种成本。事实上,在这种情况下,strstream以最小的代码开销和速度做到了您想要的效果。这与Herb Sutter在ostrsteram的讨论类似。


7
是的,但是Josuttis说“ char *流类仅保留用于向后兼容。它们的接口容易出错,而且很少被正确使用。”这就是为什么我有点不愿意使用它们的原因。“仅用于向后兼容”似乎意味着有一种更好的方法可以使用“更好”的类。 - Jean-Denis Muys
我读了那篇文章,它与我的问题直接相关。谢谢。我想我的问题已经得到解答,尽管没有对“tmp_blob.rdbuf()->pubsetbuf(blockPtr, blockLength);”方法发表评论。 - Jean-Denis Muys

5
Boost.IOStreams有一个流,它的工作方式类似于stringstream,但是它包装了一个本地数组,因此您避免了复制数据的过程。
std::stringstream总是创建它自己的内部缓冲区。

-1

未经测试,但或许值得尝试...

std::stringstream ss;
ss.write( blockPtr, blockLength );
ss.seekg(0);

然后使用ss调用setBlob函数。不过,正如jalf已经提到的那样,您仍然可以在std::stringstream中保留内部缓冲区。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接