Search code examples
c++optimizationprefixpostfix-operator

i++ less efficient than ++i, how to show this?


I am trying to show by example that the prefix increment is more efficient than the postfix increment.

In theory this makes sense: i++ needs to be able to return the unincremented original value and therefore store it, whereas ++i can return the incremented value without storing the previous value.

But is there a good example to show this in practice?

I tried the following code:

int array[100];

int main()
{
  for(int i = 0; i < sizeof(array)/sizeof(*array); i++)
    array[i] = 1;
}

I compiled it using gcc 4.4.0 like this:

gcc -Wa,-adhls -O0 myfile.cpp

I did this again, with the postfix increment changed to a prefix increment:

for(int i = 0; i < sizeof(array)/sizeof(*array); ++i)

The result is identical assembly code in both cases.

This was somewhat unexpected. It seemed like that by turning off optimizations (with -O0) I should see a difference to show the concept. What am I missing? Is there a better example to show this?


Solution

  • In the general case, the post increment will result in a copy where a pre-increment will not. Of course this will be optimized away in a large number of cases and in the cases where it isn't the copy operation will be negligible (ie., for built in types).

    Here's a small example that show the potential inefficiency of post-increment.

    #include <stdio.h>
    
    class foo 
    {
    
    public:
        int x;
    
        foo() : x(0) { 
            printf( "construct foo()\n"); 
        };
    
        foo( foo const& other) { 
            printf( "copy foo()\n"); 
            x = other.x; 
        };
    
        foo& operator=( foo const& rhs) { 
            printf( "assign foo()\n"); 
            x = rhs.x;
            return *this; 
        };
    
        foo& operator++() { 
            printf( "preincrement foo\n"); 
            ++x; 
            return *this; 
        };
    
        foo operator++( int) { 
            printf( "postincrement foo\n"); 
            foo temp( *this);
            ++x;
            return temp; 
        };
    
    };
    
    
    int main()
    {
        foo bar;
    
        printf( "\n" "preinc example: \n");
        ++bar;
    
        printf( "\n" "postinc example: \n");
        bar++;
    }
    

    The results from an optimized build (which actually removes a second copy operation in the post-increment case due to RVO):

    construct foo()
    
    preinc example: 
    preincrement foo
    
    postinc example: 
    postincrement foo
    copy foo()
    

    In general, if you don't need the semantics of the post-increment, why take the chance that an unnecessary copy will occur?

    Of course, it's good to keep in mind that a custom operator++() - either the pre or post variant - is free to return whatever it wants (or even do whatever it wants), and I'd imagine that there are quite a few that don't follow the usual rules. Occasionally I've come across implementations that return "void", which makes the usual semantic difference go away.