views:

117

answers:

3

The C++ comma operator is used to chain individual expressions, yielding the value of the last executed expression as the result.

For example the skeleton code (6 statements, 6 expressions):

step1;
step2;
if (condition)
    step3;
    return step4; 
else
    return step5;

May be rewritten to: (1 statement, 6 expressions)

return step1, 
       step2,
       condition?
          step3, step4 : 
          step5;

I noticed that it is not possible to perform step-by-step debugging of such code, as the expression chain seems to be executed as a whole. Does it means that the compiler is able to perform special optimizations which are not possible with the traditional statement approach (specially if the steps are const or inline)?

Note: I'm not talking about the coding style merit of that way of expressing sequence of expressions! Just about the possible optimisations allowed by replacing statements by expressions.

A: 

Very unlikely IMHO. The thing get's compiled down to assembler/machine code, then further low-level optimizations are done, so it probably turns out to the same thing.

OTOH, if the comma operator is overloaded, the game changes completely. But I'm sure you know that. ;)

The obligatory list:

  1. Don't worry about rewriting almost equivalent code to gain performance
  2. If you have a perf-problem, profile to see what the problem is
  3. If you can't get it faster by algorithmic ops, look at the disassembly and see that the compiler does what you intended
  4. If not, ask here and post source and disassembly for both versions. :)
Marcus Lindblom
+1  A: 

Using the comma operator neither promotes nor hinders optimization in any circumstances I'm aware of, because the C++ standard guarantee is only that evaluation will be in left-to-right order, not that statement execution necessarily will be. (This is the same guarantee you get with statement line order.)

What it is likely to do, though, is turn your code into a confusing mess, since many programmers are unaware that the comma-as-operator even exists, and are apt to confuse it with commas used as parameter separators. (Want to really make your code unreadable? Call a function like my_func((++i, y), x).)

The "best" use of the comma operator I've seen is to work with multiple variables in the iteration statement of a for loop:

for (int i = 0, j = 0; 
     i < 10 && j < 12; 
     i += j, ++j) // each time through the loop we're tinkering with BOTH i and j
{
}
Dan Story
+6  A: 

Most compilers will break your code down into "basic blocks", which are stretches of code with no jumps/branches in or out. Optimisations will be performed on a graph of these blocks: that graph captures all the control flow in the function. The basic blocks are equivalent in your two versions of the code, so I doubt that you'd get different optimisations. That the basic blocks are the same isn't entirely obvious: it relies on the fact that the control flow between the steps is the same in both cases, and so are the sequence points. The most plausible difference is that you might find in the second case there is only one block including a "return", and in the first case there are two. The blocks are still equivalent, since the optimiser can replace two blocks that "do the same thing" with one block that is jumped to from two different places. That's a very common optimisation.

It's possible, of course, that a particular compiler doesn't ignore or eliminate the differences between your two functions when optimising. But there's really no way of saying whether any differences would make the result faster or slower, without examining what that compiler is doing. In short there's no difference between the possible optimisations, but it doesn't necessarily follow that there's no difference between the actual optimisations.

The reason you can't single-step your second version of the code is just down to how the debugger works, not the compiler. Single-step usually means, "run to the next statement", so if you break your code into multiple statements, you can more easily debug each one. Otherwise, if your debugger has an assembly view, then in the second case you could switch to that and single-step the assembly, allowing you to see how it progresses. Or if any of your steps involve function calls, then you may be able to "do the hokey-cokey", by repeatedly doing "step in, step out" of the functions, and separate them that way.

Steve Jessop