非复制 istringstream

问题描述 投票:0回答:6

因此

istringstream
在初始化时复制字符串的内容,例如

string moo("one two three four");
istringstream iss(moo.c_str());

我想知道是否有办法让

std::istringstream
使用给定的
c_str
作为缓冲区而不复制内容。这样,在将
std::istringstream&
传递给以
istream&
作为参数的函数之前,就不必复制大量内存。

我一直在尝试做的是将一些只接受

std::ifstream&
参数的函数(它们主要是解析器)转换为也接受
istream&
。我是否必须为此创建自己的
istream
子类?

c++ istream istringstream
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()
的调用会导致一些复制,尽管我不知道它的任何实现。


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_
}

2
投票

只有一个副本,因为您传递的参数

const char*
需要转换为istringstream构造函数的参数类型。

只需传入

string
,无需调用
c_str()

istringstream iss(moo);

好吧,这并不能完全阻止复制,但它消除了不必要的复制。要完全消除副本,您必须重写

std::stringbuf
,这特别避免直接在您提供的
string
上工作。


2
投票

这取决于 std::string 的作用。根据 27.2.1/1

The class basic_istringstream<charT,traits,Allocator> ... uses a basic_stringbuf<charT,traits,Allocator> object to control the associated storage.
由于类必须使用对象,因此必须将字符串复制构造到该对象中。

因此,真正的问题不是

stringstream
是否复制内容,而是复制构造字符串是否会复制内容或实现某种写时复制方案。


0
投票

经过几天的搜索和尝试各种方法包括scnlib、sscanf、istringstream等,也许我找到了答案。如果您关心解析性能,则应该使用 C++17 中添加的

charsconv header
中的 from_chars 系列函数。这是在 C++ 中快速解析
string_view
的唯一合理解决方案。

根据cppreference

与 C++ 和 C 库中的其他解析函数不同,std::from_chars 与语言环境无关、不分配、不抛出。仅提供其他库(例如 std::sscanf)使用的一小部分解析策略。这样做的目的是允许尽可能快的实现,这在常见的高吞吐量上下文中非常有用,例如基于文本的交换(JSON 或 XML)。

其他方法存在的问题如下:

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

istringstream: 正如问题所说,它无法处理作用域,并且不可避免地需要在初始化时进行副本。

sscanf: C 风格的空终止字符串是必要的,而根据 cppreference,某些实现同样可能会导致性能问题。

© www.soinside.com 2019 - 2024. All rights reserved.