用C ++读取大字符串 - 是否有安全快速的方法?

时间:2016-09-07 22:15:07

标签: c++ string file stl

http://insanecoding.blogspot.co.uk/2011/11/how-to-read-in-file-in-c.html回顾了在C ++中将整个文件读入字符串的多种方法。最快选项的关键代码如下所示:

std::string contents;
in.seekg(0, std::ios::end);
contents.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&contents[0], contents.size());

不幸的是,这不安全,因为它依赖于以特定方式实施的string。例如,如果实现是共享字符串,那么修改&contents[0]处的数据可能会影响正在读取的字符串。 (更一般地说,不能保证这不会破坏任意记忆 - 在实践中不太可能发生,但依靠它不是好习惯。)

C ++和STL旨在提供高效的C语言功能,因此可以预期上述版本的速度同样快,但保证安全。

vector<T>的情况下,有一些函数可用于访问原始数据,可用于有效地读取向量:

T* vector::data();
const T* vector::data() const; 

其中第一个可用于有效地阅读vector<T>。不幸的是,string等效提供const变体:

const char* string::data() const noexcept;

所以这不能用于有效地读取字符串。 (可能省略了non-const变体以支持共享字符串实现。)

我还检查了字符串构造函数,但是那些接受char*复制数据的构造函数 - 没有选项可以移动它。

是否有安全快捷的方法将文件的全部内容读入字符串?

值得注意的是,我想要阅读string而不是vector<char>,以便我可以使用istringstream访问结果数据。对于vector<char>,没有相同的内容。

2 个答案:

答案 0 :(得分:2)

如果您确实想要避免复制,可以将文件粘贴到std::vector<char>,然后滚动自己的std::basic_stringbuf以从向量中提取数据。

然后,您可以声明std::istringstream并使用std::basic_ios::rdbuf将输入缓冲区替换为您自己的输入缓冲区。

需要注意的是,如果您选择致电istringstream::str,则会调用std::basic_stringbuf::str并需要副本。但是,听起来你似乎不需要这个功能,并且实际上可以将其删除。

这种方式是否能获得更好的性能需要实际测量。但至少你要避免在复制过程中必须有两个大的连续内存块。此外,如果您想要处理无法在连续内存中分配的真正巨大的文件,您可以使用std::deque之类的东西作为底层结构。

还值得一提的是,如果您真的只是流式传输数据,那么通过首先将其读入字符串,您实际上是双缓冲。除非你还要求内存中的内容用于其他目的,否则std::ifstream内的缓冲可能就足够了。如果你啜饮文件,你可以通过关闭关闭来获得提升。

答案 1 :(得分:1)

我认为使用&string[0]很好,它应该适用于广泛使用的标准库实现(即使它在技术上是UB)。

但是既然你提到要将数据放入istringstream,这里有另一种选择:

  1. 将数据读入char数组(new char[in.tellg()]
  2. 构建stringstream(不带领先'i')
  3. 使用stringstream::write
  4. 插入数据

    istringstream无论如何都必须复制数据,因为据我所知,std::stringstream内部并未存储std::string,因此您可以离开{{ 1}}离开并直接将数据放入其中。

    编辑:实际上,您也可以使用您提及的std::string代替手动分配(或make_unique)。