Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer dereferencing overhead vs branching / conditional statements

In heavy loops, such as ones found in game applications, there could be many factors that decide what part of the loop body is executed (for example, a character object will be updated differently depending on its current state) and so instead of doing:

void my_loop_function(int dt) {
  if (conditionX && conditionY) 
    doFoo();
  else
    doBar();

  ...
}

I am used to using a function pointer that points to a certain logic function corresponding to the character's current state, as in:

void (*updater)(int);

void something_happens() {
  updater = &doFoo;
}
void something_else_happens() {
  updater = &doBar;
}
void my_loop_function(int dt) {
  (*updater)(dt);

  ...
}

And in the case where I don't want to do anything, I define a dummy function and point to it when I need to:

void do_nothing(int dt) { }

Now what I'm really wondering is: am I obsessing about this needlessly? The example given above of course is simple; sometimes I need to check many variables to figure out which pieces of code I'll need to execute, and so I figured out using these "state" function pointers would indeed be more optimal, and to me, natural, but a few people I'm dealing with are heavily disagreeing.

So, is the gain from using a (virtual)function pointer worth it instead of filling my loops with conditional statements to flow the logic?

Edit: to clarify how the pointer is being set, it's done through event handling on a per-object basis. When an event occurs and, say, that character has custom logic attached to it, it sets the updater pointer in that event handler until another event occurs which will change the flow once again.

Thank you

like image 890
amireh Avatar asked Sep 19 '11 06:09

amireh


2 Answers

The function pointer approach let's you make the transitions asynchronous. Rather than just passing dt to the updater, pass the object as well. Now the updater can itself be responsible for the state transitions. This localizes the state transition logic instead of globalizing it in one big ugly if ... else if ... else if ... function.

As far as the cost of this indirection, do you care? You might care if your updaters are so extremely small that the cost of a dereference plus a function call overwhelms the cost of executing the updater code. If the updaters are of any complexity, that complexity is going to overwhelm the cost of this added flexibility.

like image 159
David Hammen Avatar answered Sep 19 '22 12:09

David Hammen


I think I 'll agree with the non-believers here. The money question in this case is how is the pointer value going to be set?

If you can somehow index into a map and produce a pointer, then this approach might justify itself through reducing code complexity. However, what you have here is rather more like a state machine spread across several functions.

Consider that something_else_happens in practice will have to examine the previous value of the pointer before setting it to another value. The same goes for something_different_happens, etc. In effect you 've scattered the logic for your state machine all over the place and made it difficult to follow.

like image 29
Jon Avatar answered Sep 20 '22 12:09

Jon