Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading operators : const vs non-const return type : any difference of performance?

If we go to the wikipedia article about C++ operators, we have as an example :

Addition : a + b -> T T::operator +(const T& b) const;

So the operator return a non-const of type T. If we look at this guideline the author say that the return type should be a const to avoid the following syntax :

(a+b) = c

Now assume that this syntax doesn't bother me, and consider that a and b are large arrays. From a "pure" performance point of view, can the absence of the const keyword in the return type prevent optimizations from the compiler (g++ and intel icpc with -O3) ? And if the aswer is "yes", why ?

like image 406
Vincent Avatar asked Aug 12 '12 02:08

Vincent


2 Answers

This is an interesting question. In C++03, there would be no better chances to optimize with either of the two options and it would be a matter of style choice (I myself don't believe on the whole return by const to avoid unlikely errors).

In C++11, on the other hand, it might actually have an impact. In particular, if your type supports move operations, and the copy/move out of the returned value cannot be elided, then by returning by const you are effectively disabling moves *

// T is move assignable, with the usual declaration of a move assignment operator
T f();
const T g();
int main() {
   T t;
   t = f();     // can move
   t = g();     // cannot move!!!
}

In your particular case, it depends on what large arrays means for you, if they are std::array (or otherwise arrays with automatic storage), then they cannot be moved, so this would not be an option anyway, but if the large arrays are dynamically allocated memory, moving will be much more efficient than copying. Note that in C++11 is the presence rather than the absence of const that can cause a performance penalty.


* This is not 100% true, if the move assignment operator took the argument by rvalue-reference to const, then it could be moved. But none of the types in the standard library takes the argument this way, and I would not expect people to do it either (it would require const_cast inside the move operation (either constructor/assignment) and it just makes no sense: if you plan on moving (stealing) from it, why would you claim not to modify it??

like image 197
David Rodríguez - dribeas Avatar answered Nov 05 '22 15:11

David Rodríguez - dribeas


Since you're returning a temporary rvalue instance of type T, this statement doesn't do anything unless there are some global side-effects in the assignment operation, such as modifications to static variables that are data members of the type T, output to a terminal, etc. Therefore depending on the type, and whether the assignment operator is a compiler default assignment operator, this entire operation may be safely elided in an optimization pass. If there is a user-defined assignment operator for type T, then the assignment operation won't be elided, but as mentioned before, unless there are global side-effects, this won't do anything past the life-time of the statement's execution since you are not storing the value of c in an object that resides in a named and accessible memory location.

Keep in mind that if you do declare the return T type as const, and your operator method is not a const class method, you will disable certain types of operator chaining, as well as a host of other useful things, such as calling methods that have side-effects. For instance:

(a+b).print(); //assuming print() is non-const method

or assuming operator+ is not a const class method,

d = (a+b) + c;
like image 30
Jason Avatar answered Nov 05 '22 14:11

Jason