From the perspective of maintainable software, having a class for low-level tasks and individual observers is very useful. However, this particular implementation of object oriented behaviors can have its costs. All behaviors must be exposed as tasks when they are added to the scheduler, which requires many small memory allocations. On top of that, all the function calls are virtual — which adds a non-negligible overhead on most platforms.
In plain C, having tasks as function pointers would resolve these performance problems, but it would exclude most object oriented designs that are common in C++. Having unique tasks for certain NPC for example would be much harder to achieve.
Conceptually, closures are the solution to this problem. A closure is a function that has its own execution environment. In the case of AI logic, a task is such a closure with its own code and memory. Most languages support some kind of closures, but C++ has always had trouble with this. Anyone who has worked with function pointers knows how hard it is to deal with different types of functions (even if they have the same prototype).
Fast delegates are the answer to this C++ conundrum. Delegates are just like interfaces, but they have much lower overhead. They store only a function pointer and the associated “this” object. As such, it’s possible to implement closures with them very efficiently. Fast delegates, on most platforms, take barely 8 bytes of memory and compile down to two instructions in assembler. (Edit: Sadly, since compilers must compile C++ member function pointers with the worst case scenario in mind, the general fast delegate ends up taking up more memory and instructions than the best case C function pointer.)
The fast delegate library makes it very easy to create such closures from any type of function:









Comments
Comment on this article. | Show full forum thread.Just a note about fast delegates vs virtual function call: Visual C++ (which is the compiler that most Windows developers targets) is quite good at optimizing accesses to virtual functions. Most of the time (if not all), calling a virtual function results in two asm instructions (just like these fast delegates:
* an indexed access to the vtable - "this" is stored in ecx, which is also the vtable list address, so that's basically a mov.
* a call to the function ptr we just got
I guess that the fast delegates are essentially the same thing - although the mov instruction might be a bit faster - because it's not an indexed mov. But the speed should be comparable when you don't issue hundreds of thousands virtual function calls in yoru game loop :)
Best regards,
-- Emmanuel Deloget, GameDev.Net
But one thing that makes fast delegates so useful regardless of speed is the syntax. Function pointers in C++ are just terrible compared to most other languages, and the FastDelegate library makes it easy to treat any function in the same way.
So it's a great pattern as well as an optimization trick.
Alex