C ++字符串连接优化

时间:2017-01-25 17:01:51

标签: c++ c++11 stl language-lawyer stdstring

查看这样的代码(添加评论):

std::string some_var;
std::string some_func(); // both are defined, but definition is irrelevant
...
return "some text " + some_var + "c" + some_func(); // intentionally "c" not 'c'

我想知道, operator + std::string必须复制(在使用复制构造/赋值的意义上,而不是复制的内部缓冲区,例如SSO)适用),以及实际复制的内容。快速查看cppreference只是部分有用,因为它列出了12个(!)不同的案例。在某种程度上,我要求确认我对该页面的理解:

  • 案例1)制作lhs的副本,然后将rhs复制到此副本的末尾
  • 在C ++ 98案例2中) - 5)从char/const char*参数构造临时字符串,然后在案例1中得到结果
  • 在C ++ 11中案例2) - 5)从中构造临时字符串 char/const char*参数,然后导致案例6)或7)
  • 在C ++ 11中案例6) - 12)r值参数将使用insert/append进行变异,如果提供了char/const char*参数,则由于过载而不需要临时值insert/append。在所有情况下,返回r值以便于进一步链接。没有复制(除了要在插入位置附加/插入的参数的副本)。可能需要移动字符串的内容。

如上例所示的链应该因此导致:2) - > 6) - > 11) - > 8),没有任何lhs的副本,只是修改了第一次操作(创建临时字符串)产生的r值的缓冲区。

因此,一旦operator +=至少使用r值参数,这似乎与operator +一样有效。这是正确的吗?在C ++ 11中使用operator +=而不是operator +之后是否有任何意义,除非两个参数都是l值字符串?

编译器还可以进行哪些优化?

编辑:澄清问题的意图。初始部分仅涉及语言的细节(实施不具备);最后一个问题是关于其他优化。

1 个答案:

答案 0 :(得分:0)

字符串是一个相当不透明的对象:它包含一个内部字符缓冲区并按照它想要的方式管理它。向字符串添加单个字符可能会在分配新缓冲区,初始部分的副本和添加部分的副本时结束。全部取决于分配的缓冲区是否足够大以接受添加的部分。

报价说:

  

...没有复制(除了要在插入位置附加/插入的参数的副本)。 可能需要移动字符串的内容

不同地说新的分配,旧缓冲区的完整拷贝和释放......

当你谈到效率和优化时,你必须记住编译器不必遵循你编写程序的方式。由于 as-if 规则,只要遵守可观察的行为,它就可以优化所需的方式。 C ++标准说:

  

1.9程序执行[intro.execution]
...
  5执行格式良好的程序的符合实现应产生相同的可观察行为   作为具有相同程序的抽象机的相应实例的可能执行之一   和相同的输入。

注意事项甚至解释了:

  

实施可以自由地忽略对此的任何要求   国际标准,只要结果就好像已经遵守了要求,只要可以从中确定   程序的可观察行为。

因此,a = a + b;a += b;可能在完全相同的代码中编译。

编写C ++程序时,不应该担心低级优化:编译器会关心它,并且通常认为编译器比你更聪明。只有在确定了真正的瓶颈时才这样做,并且如果仅针对一个架构和一个配置上的一个编译器,请注意低级优化。