更新:抱歉,我错了,二进制文件+
实际上是左关联的。但是问题仍然存在,因为存在一个互补的问题。
我在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,并且也感谢移动语义等(另一个)帖子。如果这适用于此。
答案 0 :(得分:5)
虽然一元 operator+
是右关联的(就一元运算符而言),二进制 operator+
实际上是左缔合
解决您的疑虑:
string d = a + b + c;
首先会给出(a+b)
结果的临时结果。暂时没有办法,因为a和b不能改变。临时将在内存中保留至少a.size()+b.size()
个字节,a
和b
的内容将被复制到该新内存中。
然后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)
你在混淆加上一元加号。