Hello once again! I am trying to keep the pace here with the
posts and hopefully you are enjoying them. Today I will talk about Assignment #4 (PA4) – C++ Efficiency.
This assignment was a combination of three important topics about Efficiency in C++ programming: Implicit
Conversions, Return Value Optimizations and Proxy Objects. I will give you a summary of each one in the
following paragraphs:
- Implicit Conversions: the whole idea behind this trick/optimization is to prevent coders from passing wrong-typed parameters to functions. For example, imagine that you have a set function for a particular member of a class and you do not want the user to pass a value that has a different type, how can you achieve this? Aside from turning up the compiler settings (warnings), there is one trick you could use:
Class Diego {
public:
void setX( const float inX
);
private:
template <typename T> void
setX( const T inX );
}
When this trick is applied, anything but a float variable will
give a compilation error, therefore successfully preventing wrong-typed values
to be passed as parameters. Sexy or what?
- Return Value Optimizations: I will start by saying this: temporaries kill performance big time! (quoting famous philosopher Ed Keenan). The idea behind RVO is to remove as much temporary variables as possible in order to improve performance. By removing these temporaries we are also removing unnecessary calls to constructors, destructors, copy constructors, etc. Let’s look at the following example to better understand the idea:
With temporaries (No
RVO):
Vect2D
Vect2D::operator + ( const Vect2D &tmp ) const {
Vect2D sum;
sum.x = this->x + tmp.x;
sum.y = this->y + tmp.y;
return ( sum );
};
Without temporaries (RVO):
Vect2D
Vect2D::operator + ( const Vect2D &tmp ) const {
return Vect2D( this->x + tmp.x,
this->y + tmp.y );
};
You might think this change does not improve performance a
lot, but in my assignment I had a stress test in which a bunch of math
operations were performed and repeated 5 million times, and just by using RVO I improved the time to 301ms down from 939ms originally. That’s a hell of an improvement in my opinion!
- Proxy objects: this one is another trick to remove/reduce temporaries and copies from function calls. This method involves (ab)using operator overloading to: replace operations that involve more than two operands, to compare vector length using squared distance instead of square root, etc. I will show you guys an example for your entertainment and pleasure, try running/debugging it so you really understand what is going on (it took me a while to get it):
struct VaddV {
const Vect2D &v1;
const Vect2D &v2;
VaddV( const Vect2D &t1,
const Vect2D &t2 )
: v1(t1), v2(t2)
{};
operator Vect2D() {
return Vect2D(
v1.x + v2.x, v1.y + v2.y );
}
};
inline Vect2D::VaddV
operator + ( const Vect2D &a1, const Vect2D &a2 ) {
return Vect2D::VaddV(a1, a2);
};
Try performing an addition operation between three (3)
vectors and you will see this baby up and running.
Well my fellow readers, I hope these tricks are useful for
you, and if not try using them as opening lines in your next date (not
recommended). See you later! Adios!