Re: Postfix is slower than postfix: how likely?
Seungbeom Kim wrote:
It has been said for a long time that we should prefer the prefix
increment/decrement operator to the postfix because the former is never
slower and sometimes it can be faster; e.g.:
http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.15
Yes -- that's a "rule of thumb" that you can apply without thinking
about it,
and never get bitten.
Now I wonder: how likely are the cases where you suffer significant
performance loss because you use postfix instead of prefix?
I agree with your main point -- it's pretty rare that it makes a
difference
in real code. Which isn't to say that there's anything wrong with the
rule, though!
Is there
any benchmark that tells postfix can be measurably slower than prefix?
I don't know if you can call this a "benchmark" or not... but here's
a subset of a real class with a real prefix increment, to which I have
added a postfix increment and written a test driver. Compiled with
Microsoft Visual Studio .Net 2003 with full optimization, run on a
Pentium 4 2.8Ghz with 1.00 Gb of RAM on Microsoft Windows
Server 2003 Standard Edition with Service Pack 1.
// BigInt.h:
#include <iostream>
#include <ostream>
class BigInt {
public:
// Assigns base * 10^exp;
// i.e. if base=5 and exp=21, assigns
// value of 25,000,000,000,000,000,000,000
BigInt(long base=0, long exp=0);
BigInt(const BigInt &);
//~BigInt();
BigInt& operator=(const BigInt&);
std::ostream &output(std::ostream &) const;
BigInt& operator++(); // Prefix
BigInt operator++(int); // Postfix -- added
bool operator<(const BigInt &o) const
{ return compare(o)<0; }
bool operator==(const BigInt &o) const
{ return compare(o)==0; }
private:
int compare(const BigInt &) const;
enum { numdigits=100 };
char digits[numdigits];
};
inline std::ostream& operator<<(
std::ostream&o,
const BigInt&s) {
return s.output(o);
}
// BigInt.cpp
#include <cstdlib>
#include "BigInt.h"
BigInt::BigInt(long base /* =0 */, long exp /* =0 */) {
int d=0;
while (d<exp && d<numdigits)
digits[d++] = 0;
while (base && d<numdigits) {
digits[d++] = static_cast<char>(base%10);
// Ignoring negatives for now...
base /= 10;
}
while (d<numdigits)
digits[d++] = 0;
}
BigInt::BigInt(const BigInt &o) {
std::memcpy(digits, o.digits, numdigits);
}
BigInt &BigInt::operator=(const BigInt &o) {
std::memcpy(digits, o.digits, numdigits);
return *this;
}
std::ostream &BigInt::output(std::ostream &o) const {
// Find first non-zero digit
int d=0;
for (int x=1; x<numdigits; ++x)
if (digits[x]>0) d=x;
// Write them out
while (d>=0) {
o << static_cast<int>(digits[d--]);
if (d%3==2 && d>0)
o << ',';
}
return o;
}
BigInt& BigInt::operator++() {
for (int d=0;d<numdigits;++d) {
if (++digits[d]<=9) break;
digits[d]=0;
}
return *this;
}
BigInt BigInt::operator++(int) {
// Postfix -- added for this test
// Notice that the code is identical to prefix,
// except for the return type...
for (int d=0;d<numdigits;++d) {
if (++digits[d]<=9) break;
digits[d]=0;
}
return *this;
}
int BigInt::compare(const BigInt &o) const {
int result=0;
for (int d=0; d<numdigits; ++d)
if (digits[d]<o.digits[d]) result=-1;
else if (digits[d]>o.digits[d]) result=1;
return result;
}
// TestDriver.cpp
#include <ctime>
#include "BigInt.h"
int main() {
const BigInt max(5,8); // 500,000,000
time_t begin, end;
BigInt a(0);
std::cout << "Prefix: Count from " << a;
begin = time(0);
while (a<max)
++a;
end = time(0);
std::cout << " to " << a << ", elapsed: "
<< static_cast<long>(end-begin)
<< std::endl;
std::cout << std::endl;
BigInt b(0);
std::cout << "Postfix: Count from " << b;
begin = time(0);
while (b<max)
b++;
end = time(0);
std::cout << " to " << b << ", elapsed: "
<< static_cast<long>(end-begin)
<< std::endl;
}
Typical results on my computer:
Prefix: Count from 0 to 500,000,000, elapsed: 427
Postfix: Count from 0 to 500,000,000, elapsed: 475
Your results will of course differ. On another compiler with an even
better optimizer, Prefix might not be any faster than Postfix... but as
the original tip said: it sure won't ever be slower!
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]