Array of Function Pointers...
Hi,
I'm trying to pull together some code and was going to use arrays of function pointers for a few things. I was wondering what were the advantages and disadvantages of using them (in terms of speed).
Example would be using different movement functions for updating game unit's x pos.
Here's some code:
for (int nLoopNo=0; nLoopNo < Unit.count; nLoopNo++)
{
int Unit[nLoopNo].x = ((*UpdateX[Unit[nLoopNo].MovementType])(Unit[nLoopNo].x));
}
Would it be same speed, slower or faster than using if/else (considering it could be alot of units). Any thoughts would be greatly appreciated.
Thanks.
If using C++, I suggest you use virtual functions.
While they might be slower than a few if() calls, in the vast majority of cases they will run faster than an equivalent hand-written alternative (where you wouldn't pay for the virtual functions, but would pay for something even more costly).
Also, in almost every single case around here, it's faster to write (and easier to maintain) a virtual function system, as opposed to an if-based or switch-based alternative.
If using C, you can use function pointers (which will simply emulate virtual functions, but with an additional memory overhead, and less room for compiler optimization), or you can use switch statements with inlined functions. I would have done this like that:
This solution is not that hard to maintain, although it is harder than the others, and it is almost unacceptable in C++.
EDIT: also, in almost all games I've gone near as of late, the cost of moving the units was one of the smallest costs. What usually takes time, in a game is:
1- Graphics
2- Artificial Intelligence
3- Everything else
In that order. As such, I wouldn't spend so much time optimizing a part of the game that takes less than a millisecond per frame (assuming worst-case 32 millisecond frames), I'd rather spend a lot of time making it easy to expand, maintain and debug in the future.
While they might be slower than a few if() calls, in the vast majority of cases they will run faster than an equivalent hand-written alternative (where you wouldn't pay for the virtual functions, but would pay for something even more costly).
Also, in almost every single case around here, it's faster to write (and easier to maintain) a virtual function system, as opposed to an if-based or switch-based alternative.
If using C, you can use function pointers (which will simply emulate virtual functions, but with an additional memory overhead, and less room for compiler optimization), or you can use switch statements with inlined functions. I would have done this like that:
void MoveX( Unit unit ) { for( int i = 0; i < unit.count; ++i ) {#define u unit[k] switch( Unit.xMovement ) { case X_MOVEMENT_TYPE_1: u.x = xmovementtype1( u.x ); break; case X_MOVEMENT_TYPE_2: u.x = xmovementtype2( u.x, u.y ); break; } }}
This solution is not that hard to maintain, although it is harder than the others, and it is almost unacceptable in C++.
EDIT: also, in almost all games I've gone near as of late, the cost of moving the units was one of the smallest costs. What usually takes time, in a game is:
1- Graphics
2- Artificial Intelligence
3- Everything else
In that order. As such, I wouldn't spend so much time optimizing a part of the game that takes less than a millisecond per frame (assuming worst-case 32 millisecond frames), I'd rather spend a lot of time making it easy to expand, maintain and debug in the future.
Yep. The whole virtual inheritance thing in C++ is implemented via function pointers, so don't do it the hard way (i.e. by yourself) - that's effectively making the claim that you can write and debug this arcane stuff correctly and make it work faster than the guys who wrote your compiler can - and pride goeth before destruction. :/
Thanks for the suggestions.
I guess I came to the right forum to get the right answer - quick too. I'll start my progy out simple (easy to debug) and when completed tweak the speed.
I needed someone pointing me in the right direction, thanks.
I guess I came to the right forum to get the right answer - quick too. I'll start my progy out simple (easy to debug) and when completed tweak the speed.
I needed someone pointing me in the right direction, thanks.
Quote:Original post by ToohrVyk
If using C, you can use function pointers (which will simply emulate virtual functions, but with an additional memory overhead, and less room for compiler optimization)
How do function pointers cause memory overhead when comparing to virtual functions in C++. I guess its actually the other way around. You right about the optimization part though.
In terms of ASM generated:
with a function pointer the call is:
It is faster than using switch or if else...
For the application you want to use them for, function pointers are faster than classes with virtual functions, but using virtual functions may be more intuitive...it's a matter of preference really (and how pressing your need to optimise is :).
e.g.:
with a function pointer the call is:
movl func_ptr, %eax call *%eax
with a straight call it is: call func
so the speed overhead isn't much compared to all the other stuff going on in your program...It is faster than using switch or if else...
For the application you want to use them for, function pointers are faster than classes with virtual functions, but using virtual functions may be more intuitive...it's a matter of preference really (and how pressing your need to optimise is :).
e.g.:
int move_unit_soldier( int x ) { ... };int move_unit_civilian( int x ) { ... };Unit u[2];u[0].move = move_unit_soldier;u[1].move = move_unit_civilian;for ( int i = 0; i < 2; ++i ) u.x = u.move( u.x );
## as opposed to ##Class Unit {public: virtual Move() = 0; virtual GetX() const { return x; };private: int x;};class Soldier : public Unit {public: virtual Move() { x = ... };}class Civilian : public Unit {public: virtual Move() { x = ... };}Unit *u[2];u[0] = new Soldier;u[1] = new Civilian;for ( int i = 0; i < 2; ++i ) u->move();
This is the test I ran to see what would be faster and they ended up being the same.
long Function1(long nCounter)
{
nCounter++;
return nCounter;
}
long Function2(long nCounter)
{
nCounter++;
return nCounter;
}
long Function3(long nCounter)
{
nCounter++;
return nCounter;
}
long Function4(long nCounter)
{
nCounter++;
return nCounter;
}
long Function5(long nCounter)
{
nCounter++;
return nCounter;
}
long FunctionIFTHEN(int nRandomNo, long nCounter)
{
if (nRandomNo == 0) nCounter++;
if (nRandomNo == 1) nCounter++;
if (nRandomNo == 2) nCounter++;
if (nRandomNo == 3) nCounter++;
else nCounter++;
return nCounter;
}
//FUNCTION POINTER TEST
long (*IsAbove50[])(long nRandomNo)=
{
Function1, Function2, Function3, Function4, Function5
};
long nCounter = 0;
time (&tStart);
for (int n=0;n<200000000;n++)
{
int nRandomNo = rand()%5;
nCounter = ((*IsAbove50[nRandomNo])(nCounter));
}
time (&tEnd);
tDif = difftime(tEnd,tStart);
//tDif = 22 secs
//IFTHEN TEST
nCounter = 0;
time (&tStart);
for (int n=0;n<200000000;n++)
{
int nRandomNo = rand()%5;
nCounter = FunctionIFTHEN(nRandomNo, nCounter);
}
time (&tEnd);
tDif = difftime(tEnd,tStart);
//tDif = 22 secs
Perhaps the reason is that when compiled they run the same anyways. Well, I re-wrote a simplified version of my program today. Ill just keep both of them handy and optimize on a 'need to' basis. I am going to experiment with some of the suggestions you guys have given.
Thanks again for the advice.
long Function1(long nCounter)
{
nCounter++;
return nCounter;
}
long Function2(long nCounter)
{
nCounter++;
return nCounter;
}
long Function3(long nCounter)
{
nCounter++;
return nCounter;
}
long Function4(long nCounter)
{
nCounter++;
return nCounter;
}
long Function5(long nCounter)
{
nCounter++;
return nCounter;
}
long FunctionIFTHEN(int nRandomNo, long nCounter)
{
if (nRandomNo == 0) nCounter++;
if (nRandomNo == 1) nCounter++;
if (nRandomNo == 2) nCounter++;
if (nRandomNo == 3) nCounter++;
else nCounter++;
return nCounter;
}
//FUNCTION POINTER TEST
long (*IsAbove50[])(long nRandomNo)=
{
Function1, Function2, Function3, Function4, Function5
};
long nCounter = 0;
time (&tStart);
for (int n=0;n<200000000;n++)
{
int nRandomNo = rand()%5;
nCounter = ((*IsAbove50[nRandomNo])(nCounter));
}
time (&tEnd);
tDif = difftime(tEnd,tStart);
//tDif = 22 secs
//IFTHEN TEST
nCounter = 0;
time (&tStart);
for (int n=0;n<200000000;n++)
{
int nRandomNo = rand()%5;
nCounter = FunctionIFTHEN(nRandomNo, nCounter);
}
time (&tEnd);
tDif = difftime(tEnd,tStart);
//tDif = 22 secs
Perhaps the reason is that when compiled they run the same anyways. Well, I re-wrote a simplified version of my program today. Ill just keep both of them handy and optimize on a 'need to' basis. I am going to experiment with some of the suggestions you guys have given.
Thanks again for the advice.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement