Premature optimization or am I crazy?

I recently saw a piece of code in mod.lang.C ++ that returned a link to a static integer from a function. The code was something like this

int& f() { static int x; x++; return x; } int main() { f()+=1; //A f()=f()+1; //B std::cout<<f(); } 

When I debugged the application using my cool Visual Studio debugger, I saw only one call to operator A and guessed that I was shocked. I always thought that i+=1 is equal to i=i+1 , so f()+=1 will be equal to f()=f()+1 , and I would see two calls to f() , but I only saw one. What the hell is this? Am I crazy or is my debugger crazy or is this the result of premature optimization?

+7
c ++ reference premature-optimization
source share
5 answers

This is what the Standard says about += and friends:

5.17-7: The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated only once. [...]

So, the compiler is right for this.

+27
source share

i+=1 functionally coincides with i=i+1 . It is actually implemented in different ways (basically, it is designed to optimize the optimization of the processor level).

But the essentially left side is evaluated only once. It gives a non-constant l-value that needs to be read, added and written to.

This is more obvious when creating an overloaded statement for a custom type. operator+= modifies the this instance. operator+ returns a new instance. It is usually recommended (in C ++) to write oop + = first and then write op + in terms of this.

(Note that this only applies to C ++, in C #, op+= exactly as you expected: just a short hand for op+ , and you cannot create your own op + =. It is automatically created for you from Op +)

+10
source share

Your thinking is logical, but not right.

 i += 1; // This is logically equivalent to: i = i + 1; 

But logically equivalent and identical do not match.
The code should look like this:

 int& x = f(); x += x; // Now you can use logical equivalence. int& x= f(); x = x + 1; 

The compiler will not make two function calls unless you explicitly put two function calls in the code. If you have side effects in your functions (like you), and the compiler began to add unnecessary difficulties to see implicit calls, it would be very difficult to understand the code flow and thereby make maintenance very difficult.

+9
source share

f() returns a reference to a static integer. Then += 1 adds one to this memory location - there is no need to call it twice in statement A.

+3
source share

In every language that I saw that supports the + = operator, the compiler once evaluates the left-side operand to get some type of address, which is then used both to read the old value and write the new one. The + = operator is not just syntactic sugar; as you noticed, it can get the semantics of the expression, which will be inconvenient to achieve using other means.

By the way, the "C" operators in vb.net and Pascal have a similar function. A statement like:

 'Assime Foo is an array of some type of structure, Bar is a function, and Boz is a variable.
   With Foo (Bar (Boz))
     .Fnord = 9
     .Quack = 10
   End with
will calculate the address Foo (Bar (Boz)), and then set the two fields of this structure to nine and ten. That would be equivalent in C to
   {
     FOOTYPE * tmp = Foo (Bar (Boz));
     tmp-> Fnord = 9;
     tmp-> Quack = 10;
   }

but vb.net and Pascal do not set a temporary pointer. Although VB.net can achieve the same effect without using ā€œCā€ to hold down the result of Bar (), using ā€œCā€ avoids the temporary variable.

0
source share

All Articles