Prefix vs. Postfix Increment and Decrement Operators in C++
Here is how most programmers new to C-based languages are taught to write for a loop:
for (int i = 0; i < someValue; i++) {
// Do something
}
Unfortunately this starts programmers off on the wrong foot by teaching them the bad habit of using i++ (postfix increment) as the default way to increment a value. Using ++i (prefix increment) would work just as well since the result of the increment expression is not used by the containing expression (the for loop). Here is the equivalent code using ++i1:
for (int i = 0; i < someValue; ++i) {
// Do something
}
It’s preferable to use prefix increment when the result of the increment is not used by the containing expression. To see why, let’s first take a look at what the compiler generates when it encounters i++ and ++i.
First, i++:
// The compiler turns i++ into the following int temp = i; i = i + 1; return temp;
Next, ++i:
// The compiler turns ++i into the following i = i + 1; return i;
The compiler, upon seeing i++, creates a temporary object to hold the original value of i so that after the increment completes the original value of i can be returned. A temporary is not required when compiling ++i since the value returned by the increment operation is the value i has after the increment has completed. This means that i++ requires more memory and runs more slowly than ++i (space is required for the temporary and time must be spent copying the original value of i into the temporary).
The compiler can optimize away this temporary (effectively turning i++ into ++i) for built in types (such as int) in situations where the result of the increment is not used in the containing expression (as in this for loop example). This optimization is possible because the compiler can see that the temporary value that gets returned is never unused. Choosing between i++ and ++i for built in types doesn’t matter because the compiler will always optimize i++ into ++i where possible.
In C++ the increment/decrement operators can be invoked on user defined types as well as built in type by using operator overloading. Incrementing/decrementing objects of user-defined types frequently occurs when using iterators in C++:
slist<int>::iterator end = sListOfInts.end(); // Type slist defined by 3rd party
for (slist<int>::iterator i = sListOfInts.begin(); i != end; i++) {
// Do something
}
The compiler cannot optimize i++ into ++i in this situation because it has no way of knowing whether the requested call to postfix slist<int>::operator++ can be safely substituted with a call to prefix slist<int>::operator++. The compiler cannot know whether this substitution is safe, because the user could have implemented these two functions to have drastically different semantics. Of course, if the prefix and postfix versions of operator++ were sanely implemented, such a substitution would be safe because these operators would only differ in the value they return. But alas, because the compiler can’t know, and because you’ve asked for i++, that is what you’ll get. An unnecessary temporary object will be created resulting in less efficient code than if you had invoked ++i2.
You can optimize your code by always using the prefix version. As long as you are incrementing on objects with sane implementations of prefix and postfix increment you are guaranteed to execute the optimal increment (prefix). Here is the better way to code this loop:
list<int>::iterator end = someListOfInts.end();
for (list<int>::iterator i = someListOfInts.begin(); i != end; ++i) {
// Do something
}
In conclusion, always use the postfix increment/decrement operators when the containing expression does not make use of the result of the increment/decrement. This results in code that is always optimized regardless of the data type of the object being incremented/decremented. If you’re using C there is no difference but you should still prefer to use the prefix version because if your code is ever ported to C++ it will follow a convention that results in optimal performance for all incrementable/decrementable types in C++.
1 In one of the classes I took in college a teacher’s assistant docked me points on an exam for using ++i instead of i++ to increment the loop counter in a for loop. After explaining that there was no difference the points were given back but this showed the danger of following “standard” programming patterns without understanding the implications (see cargo cult programming).
2 The compiler can optimize postfix increment/decrement for non-built in types that are part of the standard library (e.g. iterators into list, map, etc.). This is possible because these types and their semantics are defined as part of the C++ standard; e.g. the compiler can be implemented to know that for a given standard type the prefix version of operator++ does not differ semantically from the postfix version of operator++ in ways other than the value returned. For non-standard types (i.e. all other user-defined types) the compiler cannot perform this optimization because the compiler has no way of knowing what semantics the user has coded into the prefix and postfix operators (i.e. the user can make these operators do anything the user wants). Note, any author overloading the prefix and postfix versions operator++/operator– to have semantics different in ways other than the value returned should be stripped of their programmer’s license!
2 Comments
Leave a comment
Recent Posts
- iOS Unit Testing With OCMock
- Why Stakeholders Need To Be Involved In Scrum
- NuGet Config File Transformation Causes Duplicate Entries On Update
- Load Testing with Locust on Windows
- Writing A Custom LINQ Provider With Re-linq
- AutoMapper Profile Organization
- Rails 3.2: A Nested-Form Demo Part 4: Switch to Targeting Computer!
- SharpRepository: Configuration
- Rails 3.2: A Nested-Form Demo, Part 3: We’re Starting Our Attack Run!
- Rails 3.2: A Nested-Form Demo, Part 2: Accelerate to Attack Speed!
- Rails 3.2: A Nested-Form Demo, Part 1: All Wings Report In!
- iOS Behind the Curve
- Distributed Transaction Coordinators, Port 135, and Firewalls – Oh My!
- SharpRepository: Getting Started
- Find Performance Problems Using JMeter, MySQL and Xdebug/Webgrind
- Taming Hot Key Context Shifting When Running A Windows VM In Virtualbox On OSX
- Integrating Twitter’s Bootstrap Into Your Project
- Mobile payments, tags and more using NFC
- Stress Pig
- Dear Client Services, What Works?
- What Would Steve Do?
- Still Using Fiddler to Test & Debug Your REST Services?
- Write-through and Generational Caching Make a Great Team
- Thinking Recursively
- Development Incentives, What’s the Payoff?
- How do you like them Apples?
- “Optional” Software Development Practices Series — Code Review
- Adding Images to Select Lists in MVC3
- “Optional” Software Development Practices Series
- You Get What You Pay For…
- Outsourcing Safety Tips
- Facebook IPO
- The Ballad of Tim Toady
- The Little Schemer
- Newsflash: Mom leaves tech job at 5p.m.
- Flashback!
- I <negative_emotion> Windows 8!
- Prefix vs. Postfix Increment and Decrement Operators in C++
- Corporate videos: viral boon or epic fail?
- Recruitin’ Time!
- Reference vs. pointer parameters in C++
- The IE8 "hover" Bug: The Most Awesome IE Bug Ever?
- When is perfect perfect enough?
- SOPA/PIPA: Anti-Censorship Protest or Techies Revenge?
- A Decade of Fairway
- Handling Session Timeout Gracefully
- Generating Software Diagrams
- The Audacity of Nope
- The Origins of Culture
- Scrum Overview in Prezi – not another boring slideshow
- Numbers don’t lie: LinkedIn Statistics
- What is your favorite software development tool?
- Best Practices for Selecting Onshore, Nearshore or Offshore Information Technology Outsourcing (ITO) Providers
- Sign of the Times
- Advantages and Risks of Offshoring, Nearshoring or Onshoring
- Does Outsourcing Mean Offshoring?
- Too little, too late?
- New Favorite Lunch Spot
- Why should I care about functions as first-class citizens?
- PHP Remote Debugging with XDebug and NetBeans
- Installing SubText with Web PI
- ROI Primer
- Learn Domain-Driven Design
- Learn Behavior-Driven Development
- Mario Kart Tournament
- F# in 90 Seconds
- Website Vulnerabilities
- Scrum Overview
- Language Club
- Top 12 Favorite Podcasts Ever…
- Fairway Dart Tournament
- Learn Lean Software Development and Kanban Systems
- Android – Eclipse Quick Start
- Learn Functional Programming
- Backup & Restore Strategy
- Smartphone Screens – Another Wireless Variable
- Wireless Application Market
- Head First AOP






I have a question purely out of curiosity, and google has been no help. I was actually taught to use ++i instead of i++ to increment for loops because it’s slightly faster, but I just wonder what’s the point of using prefix and postfix operators anyways? All it does is call a function adding 1 anyways. I don’t see how it helps with code readability or anything.
function(variable++)
vs.
function(variable)
variable+=1 or variable=variable+1
Actual implementation seems to be the same and all it does is reduce number of lines a bit. What am I missing?
Jay,
The pre/post increment/decrement operators can be implemented more efficiently on some machines. For example, on some machines there are dedicated instructions for incrementing and decrementing by 1 which will run more quickly than an addition followed by an assignment. Granted, if you are adding by one then assigning the result into the original variable the compiler should be smart enough to figure this out and turn the more lengthy code into an increment. But, it’s best not to rely on compiler optimizations if you don’t have to so the increment/decrement operators should be used when the change is only by one.
Another reason to prefer increment/decrement is because the code is shorter. Shorter code is generally easier to read once you’re use to the operations.
In your example, however, I would prefer not using the increment operator on the same line as the function call. Here is the example you gave:
function(variable++);I don’t like writing code like this because there are two logical operations taking place: 1. Calling a function, 2. Modifying the value of variable. Writing statements that perform multiple logical operations results in harder-to-read code in my opinion. I would prefer to write that code as follows:
function(variable);++variable; // Moved to it's own line so it's not missed
Thanks,
Ray