当前位置:  开发笔记 > 编程语言 > 正文

C++中的高效字符串连接

如何解决《C++中的高效字符串连接》经验,为你挑选了6个好方法。

我听到一些人表达了对std :: string中"+"运算符的担忧以及加速连接的各种变通方法.这些都真的有必要吗?如果是这样,在C++中连接字符串的最佳方法是什么?



1> Brian R. Bon..:

额外的工作可能不值得,除非你真的需要效率. 只需使用operator + =,您可能会有更好的效率.

现在在免责声明之后,我将回答你的实际问题......

STL字符串类的效率取决于您正在使用的STL的实现.

您可以通过c内置函数手动连接来保证效率更好地控制自己.

为什么operator +效率不高:

看看这个界面:

template 
basic_string
operator+(const basic_string& s1,
          const basic_string& s2)

您可以看到每个+后都返回一个新对象.这意味着每次都使用新的缓冲区.如果你正在做大量的额外+操作,那就没有效率了.

为什么你可以提高效率:

您保证效率,而不是相信代表有效地为您做到这一点

std :: string类对字符串的最大大小一无所知,也不知道你连接它的频率.您可能拥有此知识,并且可以根据获取此信息来执行操作.这将减少重新分配.

您将手动控制缓冲区,这样您就可以确保在不希望发生这种情况时不会将整个字符串复制到新的缓冲区中.

您可以将堆栈用于缓冲​​区而不是堆,这样可以提高效率.

string +运算符将创建一个新的字符串对象,并使用新的缓冲区返回它.

实施的考虑因素:

跟踪字符串长度.

保持指向字符串末尾和开头的指针,或者只是开始,并使用start + the length作为偏移量来查找字符串的结尾.

确保存储字符串的缓冲区足够大,因此您无需重新分配数据

使用strcpy而不是strcat,因此您不需要遍历字符串的长度来查找字符串的结尾.

绳索数据结构:

如果您需要非常快速的连接,请考虑使用绳索数据结构.


注意:"STL"是指一个完全独立的开源库,最初由HP提供,其中一部分用作ISO标准C++库部分的基础.但是,"std :: string"从来都不是HP STL的一部分,所以将"STL和"字符串"引在一起是完全错误的.
你能否澄清或给出一些原因**你可以使用堆栈作为缓冲区而不是堆更高效.**?这种效率差异来自哪里?
附注:负责维护STL多年的SGI员工是Matt Austern,同时也是ISO C++标准化委员会的图书馆小组的负责人.

2> Carlos A. Ib..:

之前保留最后一个空格,然后使用带缓冲区的append方法.例如,假设您希望最终的字符串长度为100万个字符:

std::string s;
s.reserve(1000000);

while (whatever)
{
  s.append(buf,len);
}



3> Johannes Sch..:

我不担心.如果你在循环中执行它,字符串将始终预分配内存以最小化重新分配 - 只是operator+=在这种情况下使用.如果你手动完成,这样或更长时间

a + " : " + c

然后它正在创造临时性 - 即使编译器可以消除一些返回值副本.这是因为在连续调用时operator+它不知道引用参数是引用命名对象还是从子operator+调用返回的临时对象.在没有首先进行分析之前,我宁愿不担心它.但让我们举一个例子来证明这一点.我们首先引入括号以使绑定清晰.我将参数直接放在用于清晰的函数声明之后.在下面,我展示了结果表达式是什么:

((a + " : ") + c) 
calls string operator+(string const&, char const*)(a, " : ")
  => (tmp1 + c)

现在,在那个添加中,tmp1是第一次调用operator +并返回显示的参数.我们假设编译器非常聪明并优化了返回值副本.因此,我们最终与包含串接一个新的字符串a" : ".现在,这发生了:

(tmp1 + c)
calls string operator+(string const&, string const&)(tmp1, c)
  => tmp2 == 

将其与以下内容进行比较:

std::string f = "hello";
(f + c)
calls string operator+(string const&, string const&)(f, c)
  => tmp1 == 

它对临时和命名字符串使用相同的函数!因此编译器必须将参数复制到一个新的字符串中并附加到该字符串并从其中返回operator+.它不能记住一个临时的并追加它.表达式越大,字符串的副本就越多.

接下来,Visual Studio和GCC将支持c ++ 1x的移动语义(补充复制语义)和rvalue引用作为实验添加.这允许确定参数是否引用临时参数.这将使得这样的添加速度惊人地快,因为上述所有内容将最终出现在一个没有副本的"添加管道"中.

如果它成为瓶颈,你仍然可以做到

 std::string(a).append(" : ").append(c) ...

append调用参数追加到*this,然后返回一个引用到自己.因此,那里没有复制临时工.或者,operator+=可以使用,但你需要丑陋的括号来修复优先级.



4> Pesto..:

对于大多数应用来说,这无关紧要.只需编写代码,幸福地不知道+运算符的工作原理,只有当它成为一个明显的瓶颈时才能自己动手.


当然,对于大多数情况来说,这是不值得的,但这并没有真正回答他的问题.
从技术上讲,他问这些是否是"必要的".他们不是,这回答了这个问题.
@Pesto在编程世界中有一个变态的概念,即性能无关紧要,我们可以忽略整个过程,因为计算机的速度越来越快。问题是,这不是人们使用C ++进行编程的原因,也不是为什么他们在堆栈溢出中发布有关有效字符串连接的问题。

5> James Curran..:

与.NET System.Strings不同,C++的std :: strings 可变的,因此可以通过简单的连接来构建,就像通过其他方法一样快.


特别是如果你在启动之前使用reserve()使缓冲区足够大以获得结果.

6> Tim..:

也许是std :: stringstream而已?

但我同意这样的观点,即你应该保持它的可维护性和可理解性,然后分析一下你是否确实遇到了问题.


stringstream很慢,请参阅https://groups.google.com/d/topic/comp.lang.c++.moderated/aiFIGb6za0w
推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有