x + =比x = x + a快吗?

我正在阅读Stroustrup的“C ++编程语言”,他说在两种方式中将某些东西添加到variables

x = x + a; 

 x += a; 

他更喜欢+=因为它最有可能更好的实施。 我认为他的意思是说它的工作也更快。
但是真的吗? 如果依赖于编译器和其他东西,我该如何检查?

只要语句真的像x = x + a;一样简单,任何编译器都会为其任何内置types( intfloat等)生成完全相同的机器语言序列x = x + a; 并启用优化 。 (值得注意的是,GCC的-O0 (默认模式)执行反优化 ,例如将完全不必要的存储插入到内存中,以确保debugging器始终能够findvariables值。

如果陈述更为复杂,可能会有所不同。 假设f是一个返回指针的函数

 *f() += a; 

只调用一次,而

 *f() = *f() + a; 

称它两次。 如果f有副作用,两者中的一个将是错误的(可能是后者)。 即使f没有副作用,编译器可能无法消除第二个调用,所以后者可能确实比较慢。

由于我们在这里讨论的是C ++,对于重载operator+operator+=类types,情况完全不同。 如果x是这样一个types,那么 – 优化前 – x += a转换为

 x.operator+=(a); 

x = x + a转化为

 auto TEMP(x.operator+(a)); x.operator=(TEMP); 

现在,如果类是正确编写的而且编译器的优化器足够好的话,那么两者都将生成相同的机器语言,但是对于内置types来说这不是一个确定的事情。 这可能是Stroustrup在鼓励使用+=的时候所想的。

你可以通过查看disassembly来检查,这将是相同的。

对于基本types ,两者同样快速。

这是由debugging版本(即不进行优化)生成的输出:

  a += x; 010813BC mov eax,dword ptr [a] 010813BF add eax,dword ptr [x] 010813C2 mov dword ptr [a],eax a = a + x; 010813C5 mov eax,dword ptr [a] 010813C8 add eax,dword ptr [x] 010813CB mov dword ptr [a],eax 

对于用户定义的types ,您可以重载operator +operator += ,这取决于它们各自的实现。

是! 写的速度更快,阅读更快,而且更快捷,对于后者在x可能有副作用的情况下。 所以对人类来说总体来说更快 一般人的时间花费比电脑时间要多得多,所以一定是你所问的。 对?

x = x + ax += a之间的差别是机器必须经过的工作量 – 有些编译器可能(通常是)优化它,但通常,如果我们忽略优化一段时间,会发生什么在前面的代码片段中,机器必须两次查找x的值,而在后者中,这个查找只需要发生一次。

但是,正如我所提到的那样,今天大多数编译器都足够智能地分析指令并减less所需的机器指令。

PS:堆栈溢出的第一个答案!

这实际上取决于x和a的types以及+的实现。 对于

  T x, a; .... x = x + a; 

编译器必须创build一个临时T来包含x + a的值,同时对它进行求值,然后将其分配给x。 (在这个操作中不能使用x或者a作为工作区)。

对于x + = a,它不需要临时的。

对于琐碎的types,没有区别。

正如你已经标记了这个C ++,你无法从你发布的两条语句中知道。 你需要知道'x'是什么(有点像'42'的答案)。 如果x是一个POD,那么它不会有太大的区别。 然而,如果x是一个类,那么operator +operator +=方法可能会有重载,这些方法可能会导致不同的行为,从而导致执行时间差异很大。

如果你说+=你让编译器的生活变得更容易。 为了使编译器认识到x = x+ax += a相同,编译器必须这样做

  • 分析左手边( x )以确保它没有副作用并始终指相同的l值。 例如,它可能是z[i] ,它必须确保zi都不会改变。

  • 分析右边( x+a )并确保它是一个求和,而左边只出现一次,即使它可以被转换,就像在z[i] = a + *(z+2*0+i)

如果你的意思是要添加a x ,编译器的作者会在你说出你的意思时欣赏它。 这样一来,你就不会执行编译器的一部分,编者希望他/她能够得到所有的错误,而这实际上并不会让你的生活变得更容易,除非你真的不能把你的脑袋拿出来Fortran模式。

你问的是错误的问题。

这不太可能推动应用程序或function的性能。 即使是这样,find的方法是分析代码,并知道它如何影响你一定。 不要担心在这个层面上哪个更快,从清晰性,正确性和可读性的angular度来考虑更为重要

当你考虑到这一点时尤其如此,即使这是一个重要的性能因素,编译器也会随着时间的推移而发展。 有人可能会找出一个新的优化,今天正确的答案可能会成为错误的明天。 这是一个过早优化的经典案例。

这并不是说性能根本不重要,只是这是实现性能目标的错误方法。 正确的方法是使用分析工具来了解您的代码实际在哪里花费时间,从而在哪里集中精力。

举一个具体的例子,设想一个简单的复杂数字types:

 struct complex { double x, y; complex(double _x, double _y) : x(_x), y(_y) { } complex& operator +=(const complex& b) { x += bx; y += by; return *this; } complex operator +(const complex& b) { complex result(x+bx, y+by); return result; } /* trivial assignment operator */ } 

对于a = a + b的情况,它必须创build一个额外的临时variables,然后复制它。

我认为这应该取决于机器和它的架构。 如果其架构允许间接寻址,那么编译器作者MIGHT只是使用这个代码(用于优化):

 mov $[y],$ACC iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i" 

i = i + y可能会被翻译成(没有优化):

 mov $[i],$ACC mov $[y],$B iadd $ACC,$B mov $B,[i] 

也就是说,如果i是一个函数返回指针等其他的复杂性也应该考虑。 大多数生产级编译器(包括GCC)为这两个语句(如果它们是整数)生成相同的代码。

不,两种方式都是一样的。