我遇到需要处理大量(多GB)数据的情况:
每次迭代中的数据都是独立的。
我的问题是,我想最小化(如果可能的话)堆分配的内存使用量,因为它目前是我最大的性能问题。
有没有办法将C字符串(char *)转换为stl C ++字符串(std :: string),而不需要std :: string在内部分配/复制数据?
或者,我可以使用stringstreams或类似的东西来重用大缓冲区吗?
编辑:谢谢您的回答,为清楚起见,我认为修改后的问题将是:
如何有效地构建(通过多个附加)一个stl C ++字符串。如果在循环中执行此操作,其中每个循环完全独立,我如何重新使用此分配的空间。
答案 0 :(得分:22)
如果不复制数据,实际上无法形成std :: string。字符串流可能会重复使用内存从传递到传递(虽然我认为标准对于它是否真的必须是静默的),但它仍然无法避免复制。
解决此类问题的一种常见方法是编写在步骤3中处理数据的代码,以使用开始/结束迭代器对;然后它可以轻松处理std :: string,chars向量,一对原始指针等。与传递类似std :: string的容器类型不同,它不再知道或关心内存是如何分配的,因为它仍然属于来电者。将这个想法运用到它的逻辑结论是boost::range,它将所有重载的构造函数添加到仍然让调用者只传递字符串/ vector / list /任何类型的容器与.begin()和.end(),或者单独的迭代器。
编写处理代码以处理任意迭代器范围后,您甚至可以编写自定义迭代器(不像听起来那么难,基本上只是一个带有一些标准typedef的对象,而operator ++ / * / = / == /!=重载以获得一个前向迭代器),每当它到达它正在处理的那个片段的末尾时,它会处理前进到下一个片段,跳过空格(我假设这是你修剪的意思)。你根本不需要连续组装整个字符串。这是否会取胜取决于你拥有多少片段/片段大小。这基本上是Martin York提到的SGI绳索:一个字符串,其中append形成一个链接的片段列表而不是一个连续的缓冲区,因此适用于更长的值。
更新(因为我仍然会看到这个答案的偶尔投票):
C ++ 17引入了另一种选择:std::string_view,它在许多函数签名中替换了std :: string,是对字符数据的非拥有引用。它可以从std :: string隐式转换,但也可以从其他地方拥有的连续数据显式构造,避免不必要的复制std :: string强加。
答案 1 :(得分:18)
在步骤1中是否可以使用C ++字符串?如果使用string::reserve(size_t)
,则可以分配足够大的缓冲区以防止多个堆分配,同时附加较小的字符串,然后您可以在所有剩余步骤中使用相同的C ++字符串。
有关reserve
功能的详情,请参阅this link。
答案 2 :(得分:7)
为了帮助实现真正的大字符串,SGI在其STL中拥有Class Rope 非标准但可能有用。
http://www.sgi.com/tech/stl/Rope.html
显然绳索符合标准的下一个版本:-)
请注意开发者的笑话。绳子是一根大绳子。 (哈哈): - )
答案 3 :(得分:4)
这是一个横向思考的答案,不是直接解决问题,而是围绕它“思考”。可能有用,可能不会......
std :: string的只读处理并不需要std :: string特性的非常复杂的子集。您是否有可能在对std :: strings执行所有处理的代码上执行搜索/替换,因此需要其他类型的代码?从空白课开始:
class lightweight_string {};
然后用lightweight_string替换所有std :: string引用。执行编译以准确找出lightweight_string上需要哪些操作,以便它作为替代品。然后,您可以根据需要使您的实施工作。
答案 4 :(得分:1)
每个迭代是否足够独立,您可以为每次迭代使用相同的std :: string?人们希望你的std :: string实现足够聪明,如果在以前用于其他东西的时候为它分配一个const char *,就可以重用内存。
将char *分配给std :: string必须始终至少复制数据。内存管理是使用std :: string的主要原因之一,因此您将无法覆盖它。
答案 5 :(得分:0)
在这种情况下,最好直接处理char *,而不是将其分配给std :: string。