Sign in to follow this  
error101

Array of Function Pointers...

Recommended Posts

error101    122
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.

Share this post


Link to post
Share on other sites
ToohrVyk    1596
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:


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.

Share this post


Link to post
Share on other sites
Zahlman    1682
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. :/

Share this post


Link to post
Share on other sites
error101    122
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.

Share this post


Link to post
Share on other sites
Winograd    380
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.

Share this post


Link to post
Share on other sites
lucky_monkey    440
In terms of ASM generated:
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[i].x = u[i].move( u[i].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[i]->move();

Share this post


Link to post
Share on other sites
error101    122
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this