Avoiding function pointers in C++
Function pointers in C++ sometimes appear necessary to allow the structure of a program to be defined at runtime. However, their dereference causes an overhead. In the case of ToFeT, a single function pointer inside long lasting loop was causing a 5% hit in efficiency.
To solve this problem, James Kirkpatrick has provided an alternative solution of such elegance, and of such notable absence the fora of the web, that I summarise it here in the hope that others will find it.
James' idea is to use a templated class (in this case 'Hoppers_template'), where the functionality of the class depends on the template type. Wonderfully, everything is resolved at compile time so you don't suffer any hits at runtime. With the code below and the g++ compiler I found that the templated method is 37 % faster than the pointer method. As an added bonus, the template syntax is also a darn sight nicer to read as well...
Good work Dr. KP!
Update: The downside of using templated classes is that everything has to be defined in the header file. I suspect there's an even better solution to this problem lurking in Modern C++ Design. Once I've found it, I'll provide it here...
-------------------------------------------------------------------------------
#include <iostream>
using namespace std;
///////////////////////////////////////////////////////////////////////////////
// The fast way, with a templated class.
///////////////////////////////////////////////////////////////////////////////
template <class method> class Hoppers_template
{
private:
method m;
public:
Hoppers_template(){}
void run()
{
for (unsigned int i = 0; i < 1e9; ++i)
{
// do something...
m.run();
}
}
};
class Run
{
public:
Run(){}
void run() {}
};
///////////////////////////////////////////////////////////////////////////////
// The slow way, with a function pointer.
///////////////////////////////////////////////////////////////////////////////
class Hoppers_pointer
{
private:
void (Hoppers_pointer::*runPointer)();
void runFunction(){};
public:
Hoppers_pointer()
{
runPointer = &Hoppers_pointer::runFunction;
}
void run()
{
for (unsigned int i = 0; i < 1e9; ++i)
{
// do something...
(this->*runPointer)();
}
}
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int main()
{
// The fast, templated way:
Hoppers_template <Run> h_template;
h_template.run();
// The slow, pointer way:
Hoppers_pointer h_pointer;
h_pointer.run();
}
-------------------------------------------------------------------------------