Delegate Performance Impact

How does the performance of delegates compare to direct function calls?

Delegates do have some performance overhead compared to direct function calls. Let's break down the costs and examine when they matter.

Direct Function Calls

A direct function call is typically compiled into a single CPU instruction:

class Player {
public:
  void TakeDamage(int Damage) {
    UpdateHealthBar(Health - Damage);
  }

private:
  void UpdateHealthBar(int NewHealth) {
    std::cout << "Health: " << NewHealth << '\n';
  }

  int Health{100};
};

Delegate Calls

A delegate using std::function involves:

  • A virtual function call (typically 2-3 instructions)
  • Possible heap allocation during delegate setup
  • Small memory overhead for storing the delegate
class Player {
 public:
  using DamageDelegate = std::function<
    void(int NewHealth)>;

  void SetDelegate(DamageDelegate D) {
    OnDamage = D;  
  }

  void TakeDamage(int Damage) {
    if (OnDamage) OnDamage(Health - Damage);  
  }

 private:
  DamageDelegate OnDamage;
  int Health{100};
};

Performance Impact

For most games, this overhead is negligible. Consider:

  • Modern CPUs execute billions of instructions per second
  • Delegate calls typically happen in response to events (damage, collecting items, etc.) rather than every frame
  • The flexibility benefits often outweigh the small performance cost

However, if you're calling delegates thousands of times per frame, you might want to consider alternatives:

  • Raw function pointers (less overhead but less flexible)
  • Direct virtual function calls
  • Compile-time polymorphism using templates

The key is to profile your specific use case. Don't optimize prematurely - start with the cleaner delegate-based design, and only optimize if profiling shows it's necessary.

Delegates and the Observer Pattern

An overview of the options we have for building flexible notification systems between game components

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Why Use Delegates?
Why do we need to use delegates instead of just calling functions directly?
Handling Multiple Event Types
Can I have an observer observe multiple different types of events from the same subject?
Pausing Observer Notifications
Is it possible to temporarily pause notifications to specific observers?
std::function vs Function Pointer Performance
What's the overhead of using std::function compared to raw function pointers?
Smart Pointers with Observers
Can I use smart pointers to automatically manage observer registration/unregistration?
Observer Pattern Without Dynamic Allocation
Is it possible to implement the observer pattern without dynamic memory allocation?
Or Ask your Own Question
Purchase the course to ask your own questions