It used to be the case that pre-increment would be preferred because an overloaded post-increment on a class necessitated the return of a temporary copy that represented the state of the object before the increment.
It seems this is no longer a serious concern (so long as inlining is in place), since my old C++ compiler (GCC 4.4.7) seems to optimize the following two functions down into identical code:
class Int {
//...
public:
Int (int x = 0);
Int & operator ++ ();
Int operator ++ (int) {
Int x(*this);
++*this;
return x;
}
};
Int & test_pre (Int &a) {
++a;
return a;
}
Int & test_post (Int &a) {
a++;
return a;
}
The resulting assembly for both functions is:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
movq %rdi, %rbx
call _ZN3IntppEv
movq %rbx, %rax
popq %rbx
.cfi_def_cfa_offset 8
ret
.cfi_endproc
If nothing is inlined, however, there seems to still be a benefit to preferring pre-increment to post-increment, since
test_post
is forced to call out intooperator++(int)
.
Let's assume operator++(int)
is inlined as an idiomatic copy constructor, call to the pre-increment, and return of the copy, as illustrated above. If the copy constructor is inlined or the default copy constructor implementation, is that sufficient information for the compiler to optimize post-increment so that test_pre
and test_post
become identical functions? If not, what other information is required?
Besides being potentially more efficient, the main reason why you should (usually) prefer pre-increment over post-increment is that the former is what you really meant in the first place.
When you write a loop header like
for ( std::size_t i = 0; i < numElements; i++ )
you don't mean "pls add one to the value of i and then give me its old value". You don't care about the return value of the expression i++ at all! So why make the compiler jump through hoops and give the one return value that takes the most work to get?
I realize the compiler will usually optimize the unnecessary extra work away anyway, but why not just say what you mean instead of hoping for the compiler to figure out what you mean?
Typically the post-increment operator in user defined types involved creating a copy which is slower and more expensive than the typical pre-increment operator.
Therefore the pre-increment operator should be used in preference for user-defined types.
Also it is good style to be consistent and therefore pre-increment should also be preferred with built in types.
Example:
struct test
{
// faster pre-increment
test& operator++() // pre-increment
{
// update internal state
return *this; // return this
}
// slower post-increment
test operator++(int)
{
test c = (*this); // make a copy
++(*this); // pre-increment this object
return c; // return the un-incremented copy
}
};
The compiler can not be expected to optimise post-increment for user defined types as their implementation is a convention, not something the compiler can deduce.
Yes. It shouldn't matter for built-in types. For such types, the compiler can easily analyze the semantics and optimize them — if that doesn't change the behavior.
However, for class-type, it may (if not does) matter, because the semantic could be more complex in this case.
class X { /* code */ };
X x;
++x;
x++;
The last two calls could be entirely different and may perform different things, just like these calls:
x.decrement(); //may be same as ++x (cheating is legal in C++ world!)
x.increment(); //may be same as x++
So dont let yourself trapped for the syntactic sugar.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With