c ++ operator associativity / string concatenation / move semantics

时间:2013-08-21 12:24:38

标签: c++ c++11

更新:抱歉,我错了,二进制文件+实际上是左关联的。但是问题仍然存在,因为存在一个互补的问题。


我在C / C ++中读到,+运算符是右关联的。这意味着给定std::string s a, b, c全部初始化为某个非零长度,

string d = a + b + c;

应完全等同于(即产生相同的可执行文件)

string d = a + (b + c);

现在,这似乎是相当不幸的:将a扩展到b再扩展到c更有意义

string d = (a + b) + c;

因为在没有重新分配的情况下,应该使用b.size() + c.size()复制操作。

那么,我是否应该在实践中使用parens /单独+=分配,或者规范是否允许进一步优化以使无paren-less版本同样有效?

我在这里主要关注C ++ 11,并且也感谢移动语义等(另一个)帖子。如果这适用于此。

2 个答案:

答案 0 :(得分:5)

虽然一元 operator+是右关联的(就一元运算符而言),二进制 operator+实际上是左缔合

解决您的疑虑:

string d = a + b + c;

首先会给出(a+b)结果的临时结果。暂时没有办法,因为a和b不能改变。临时将在内存中保留至少a.size()+b.size()个字节,ab的内容将被复制到该新内存中。

然后c将添加到临时,调用operator+(string&& lhs,const string& rhs)。这将采用临时方式并将c的内容添加到其中,可能是在重新分配之后,以补偿需要更多空间并将a.size()+b.size()字节从旧内存复制到新内存。之后,c的内容将附加到新内存中的临时内容中。

然后移动构造函数将启动,获取临时内存的拥有权。

总共最多提供两次(重新)分配(每次operator+一次),一次释放(在tmp + c重新分配期间)和四份副本(a,b,c和在重新分配期间临时)。有 a.size()+b.size()复制操作,因为字符串内容可以整体复制(memcpy / memmove),因为char数组是不需要一个接一个地复制的POD。

虽然从语言/库的角度来看,没有什么可以做到这一点,优化器可以理论上看到分配和条件重新分配,并通过从一开始就保留足够的内存来做正确的事情。我不知道这样的优化是多么容易实现,但我想检测像a+b这样的事情并不容易,所以我不会指望它。

Ayways,临时工通常不会损害你的程序性能,因为像这样的字符串操作很少发生在性能关键的地方。

如果您绝对必须提升该操作的性能,那就可以了:

string z = a + b + c + d + e + f...

在预约通话期间导致一次分配,正好是三个必要的副本。

答案 1 :(得分:2)

你在混淆加上一元加号。