非复制的istringstream

17

所以,当初始化istringstream时,会复制字符串的内容,例如:

string moo("one two three four");
istringstream iss(moo.c_str());
我想知道是否有一种方法可以让std :: istringstream使用给定的c_str作为其缓冲区,而不需要复制内容。这样,在将std :: istringstream&传递给以istream&为参数的函数之前,它就不必复制大块内存了。
我一直在尝试将一些仅采用std :: ifstream&参数(它们大多是解析器)的函数转换为也采用istream&。我需要为此制作自己的istream子类吗?

参见这个答案,其中提供了一种方法(基本上与@Charles的解决方案相同,但为了方便将其包装在一个istream中)。 - Johannes Schaub - litb
6个回答

9

使用istringstream不是一个满意的解决方案,因为这会复制整个缓冲区。

之前的回答建议使用已弃用的istrstream,但由于这会生成警告并可能在未来被移除,更好的解决方案是使用boost::iostreams

boost::iostreams::stream<boost::iostreams::array_source> stream(moo.c_str(), moo.size());

这将避免像istrstream一样复制缓冲区,也可以省去编写自己的流类的麻烦。

5

编写一个基本的std::streambuf类从给定的内存区域读取是相当简单的。然后,您可以从中构造一个istream并从中读取。

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

请注意,c_str()指向的缓冲区的生命周期非常有限,并且不能保证调用c_str()不会导致一些复制,尽管我不知道任何实现会这样做。


啊,谢谢你的建议,我会试一下的。看起来比我想象的简单多了 :) - kamziro
在我的情况下,这绝对不会像istringstream一样工作,@Riot下面的解决方案确实可以按预期工作。在我的情况下,使用seekg读取时,代码更新获取指向istringstream的指针。换句话说,正确的解决方案还需要seekpos重载以匹配ostreingstream的行为。 - Pavel P

3
过时的istrstream支持此功能。
#include <string>
#include <strstream>
using namespace std;

int main(int argc, char* argv[])
{
    string moo = "one two three four";
    istrstream istr(const_cast<char*>(moo.c_str()),moo.size());
    std::string line;
    while(!istr.fail() && !istr.eof()){
        getline(istr,line,' ');
        cout << line << "_";
    }
    // prints: one_two_three_four_
}

@sbi:我的错,我之前先用了strstream做了一些测试,这是遗留下来的,现在已经修复了。 - smerlin

2

这只是一份副本,因为你传递的参数是一个const char*,需要将其转换为istringstream构造函数的参数类型。

只需传入string而不调用c_str()即可。

istringstream iss(moo);

好的,这并不能完全防止复制,但它消除了一次不必要的复制。如果要完全消除复制,您需要重写std::stringbuf,该函数专门避免直接处理您提供的string


2
这取决于std::string的行为。根据27.2.1/1中的描述,“basic_istringstream<charT,traits,Allocator>类……使用basic_stringbuf<charT,traits,Allocator>对象来控制相关存储。”由于该类必须使用对象,因此必须将字符串复制构造到该对象中。
因此,真正的问题不在于stringstream是否复制内容,而在于复制构造一个字符串是否会复制内容或实现某种写时复制方案。

0
几天来,我一直在寻找并尝试各种方法,包括scnlib、sscanf、istringstream等等,也许我找到了答案。如果你关心解析性能,你应该使用C++17中添加的charsconv头文件中的from_chars函数族。这是在C++中快速解析string_view的唯一合理解决方案。
根据cppreference的说明:

与C++和C库中的其他解析函数不同,std::from_chars是与区域设置无关、无需分配内存且不会抛出异常的。它只提供了其他库(如std::sscanf)使用的一小部分解析策略。这旨在允许实现最快速度的解析,适用于常见的高吞吐量环境,如基于文本的交换(JSON或XML)。

其他方法的问题如下:

scnlib: 我发现它的性能与输入字符串的长度有关,即使你只解析一个整数,传入一个很长的字符串也会导致线性性能下降。这对于需要高性能的场景是不可接受的。

istringstream: 正如问题所说,它无法处理作用域,并且在初始化时必然需要进行复制。

sscanf: 需要一个以空字符结尾的C风格字符串,而根据cppreference的一些实现,可能也会导致性能问题。


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