Prefer prefix operators over postfix

Tuesday, 13 August 2002

Whenever you have a choice, you should use the C++ prefix increment and decrement operators (e.g. ++i) instead of the postfix versions (e.g. i++). This will make your code more efficient, clear and consistent. This advice applies (more or less) to most languages that have both prefix and postfix operators.

1. Efficiency

Code like this is quite common:

for (i = 0; i < count; i++)
    // stuff

But consider what’s going on. The expression i++ has a value, namely the value of i before the increment. i is incremented during evaluation of the expression, but the program must keep a copy of the un-incremented i to use as the value of the expression.

In this case, of course, the compiler will probably realize that the value of the expression is not used, and can therefore avoid the copy.

But this assumes that i is an integral type. What if it’s an object with its own postfix increment operator (declared as operator++(int))? Even if the compiler can see that the expression’s value is not used, it still has to call the postfix version of the increment operator. Here’s a typical implementation of operator++, for a class called Incrementable:

// Prefix increment
const Incrementable& Incrementable::operator++()
{
    this->Increment(); // or whatever
    return *this;
}

// Postfix increment
const Incrementable Incrementable::operator++(int)
{
    Incrementable temp(*this);
    this->Increment(); // or whatever
    return temp;
}

Even allowing for typical optimizations, this still results in one useless object (temp) being copy constructed. Even if i is an integral type today, somebody might change it tomorrow to be some relatively heavyweight class type like an iterator: suddenly, you get a new object created and destroyed every time through the loop. Simply switching to ++i would avoid this waste.

2. Visibility

When used on a line by themselves, the postfix operators can become lost. Especially when incrementing long expressions, the operator is much easier to spot when it’s at the left margin, rather than surrounded on all sides by other code. Since I am all for clarity and visibility in code, I recommend prefix operators over postfix. (See also Clarifying C++ negation.)

server.start(tracker.getInstance());
theRegister->indexCounter++; // too much punctuation
cout << "Number " << server.last();
server.start(tracker.getInstance());
++(theRegister->indexCounter); // the ++ stands out on its own
cout << "Number " << server.last();

3. Consistency

Every other unary operator is a prefix operator. Postfix increment and decrement are there to fill a specific need. If you don’t need them, don’t use them; it could make your intentions unclear to a future maintainer of your code. And you should be nice to this unknown future person — it may be you!

Summary

In many cases, C++ programmers can choose between prefix and postfix operators. For maximum efficiency, visibility and consistency, prefix operators are the best choice. There may come a time when the powers that be see the error of their ways and rename the language to “++C”. But until then, we can all do our own little bit to help.

Tags:

Share this page:
  • Twitter
  • Digg
  • Slashdot
  • del.icio.us
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Reddit
  • Facebook
  • Print

10 comments

You can leave a comment, or trackback from your own site.

  1. Here’s the objdump -d a.out for a postfix loop with a simple body. I compiled this with with gcc 4.1.2, with the -ggdb option.

    The machine isn’t storing a copy of i, it just puts the i++ after the body of the loop.

    for (i = 0; i
    804835e: 8b 45 f4 mov 0xfffffff4(%ebp),%eax
    8048361: 89 45 f8 mov %eax,0xfffffff8(%ebp)
    8048364: 83 45 f4 01 addl $0×1,0xfffffff4(%ebp)
    8048368: 83 7d f4 09 cmpl $0×9,0xfffffff4(%ebp)
    804836c: 7e f0 jle 804835e

  2. Good stuff, Sam. I just talk about what compilers might do, but you go the extra mile and find out. Nice to know that gcc optimises simple loops. But I also said:

    In this case, of course, the compiler will probably realize that the value of the expression is not used, and can therefore avoid the copy.

    Even if i is an integral type today, somebody might change it tomorrow to be some relatively heavyweight class type like an iterator: suddenly, you get a new object created and destroyed every time through the loop.

    And don’t forget about visibility and consistency too, which in most cases are more important than efficiency anyway.

  3. The real reason to use prefix rather than postfix is because when you have a choice,
    you should write exactly what you mean. When
    you write postfix, you are communicating that
    you need the old value after the increment. If you don’t need the value, why in the world wold you write it that way? If you don’t need the old value, use prefix.

    Would you leave statements such as this:

    {
    int f = 0;
    // …
    f + 1;
    f – 1;
    // use f for real purpose
    }

    laying around in your code?

    Say what you mean, mean what you say.

  4. Man… what a bummer. I mostly like the postfix operator for its aesthetics in code rather than its “save the old value” functionality, though I do use that occasionally too. I wish I had known the efficiency stuff in this article before I started running rampant with postfix with almost all my code. Now since I’m anal retentive, whenever I see i++, for example, I have to switch it to ++i.

  5. Good stuff! Very well explained

  6. G.U. "saint" Lauri

    I wrote the same loop twice, the index is used for output and computation. In one loop I used the prefix operator, in the other the suffix… Who can say who is who ?

    .p2align 4,,7
    .p2align 3
    .L2:
    movl %ebx, 8(%esp)
    addl $1, %ebx
    movl $.LC1, 4(%esp)
    movl $1, (%esp)
    call __printf_chk
    cmpl $10, %ebx
    jne .L2

    .p2align 4,,7
    .p2align 3
    .L3:
    movl %ebx, 8(%esp)
    addl $1, %ebx
    movl $.LC1, 4(%esp)
    movl $1, (%esp)
    call __printf_chk
    cmpl $10, %ebx
    jne .L3

  7. @saint, that’s your optimising compiler at work.

  8. Explaination in well manner…

  9. “When you write postfix, you are communicating that
    you need the old value after the increment.”

    100% baloney, unless you also consider that when you write prefix, you are “communicating that you need the NEW value BEFORE the increment.”

Leave a comment