Monday 18 May 2009

Avoiding Temporary Objects

I was trying to find something in this very interesting book, titled "Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions" by Herb Sutter.

There was a chapter called "Temporary Objects". Curiosity got the better of me and I started reading. The book is extremely well written and the problem very well explained. Here is a summary of the Temporary Objects problem. Have a look at the book for complete details.

Consider the following peice of code:


string FindAddr( list<Employee> emps, string name )
{

for
( list<Employee>::iterator i = emps.begin();
i != emps.end();
i++ )
{

if
( *i == name )
{

return
i->addr;
}
}

return
"";
}

This short function has three unnecessary temporary objects, two subtler ones, and two red herrings.

The two more-obvious temporaries are buried in the function declaration itself:

string FindAddr( list emps, string name )

The parameters should be passed by const reference (const&) instead of by value. So they would now become const list& and const string&, respectively. Pass-by-value forces the compiler to make complete copies of both objects, which can be expensive and completely unnecessary.

The third more-obvious avoidable temporary occurs in the for loop's termination condition:

for( /*...*/ ; i != emps.end(); /*...*/ )

For most containers (including list), calling end() returns a temporary object that must be constructed and destroyed. Because the value will not change, recomputing (and reconstructing and redestroying) it on every loop iteration is both needlessly inefficient and unaesthetic. The value should be computed only once, stored in a local object, and reused.

Next, lets consider the way we increment i in the for loop:

for( /*...*/ ; i++

Postincrement is usually less efficient than preincrement because it has to remember and return its original value. An example of Postincrement implementation is as follows:


const T T::operator++(int)
{

T old( *this ); // remember our original value
++*this; // always implement postincrement
// in terms of preincrement
return old; // return our original value
}
As you can see postincrement is less efficient than preincrement. Postincrement has to do all the same work as preincrement, but in addition it also has to construct and return another object containing the original value. Since the original value is never used in the code, there is no reason to use postincrement. Preincrement should be used instead.

You can continue reading this further in chapter 6 of the book. Book details as follows:


No comments:

Post a Comment