std::function vs Function Pointer Performance

What's the overhead of using std::function compared to raw function pointers?

std::function provides more flexibility than raw function pointers but comes with some overhead. Let's examine the differences and when each might be appropriate.

Raw Function Pointers

Function pointers are simple and lightweight:

  • Fixed size (typically 8 bytes on 64-bit systems)
  • No heap allocation
  • Very fast to call (similar to regular function calls)
class Player {
public:
  using FnPtr = void(*)(int NewHealth);

  void SetDelegate(FnPtr Fn) {
    OnDamage = Fn;
  }

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

private:
  FnPtr OnDamage{nullptr};
  int Health{100};
};

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

int main() {
  Player P;
  P.SetDelegate(LogHealth);
  P.TakeDamage(30);
}

std::function

std::function is more flexible but has overhead:

  • Variable size (typically 32 bytes for the object itself)
  • May require heap allocation for larger callables
  • Slightly slower call time due to type erasure
class Player {
 public:
  using Delegate = std::function<
    void(int NewHealth)>;

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

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

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

int main() {
  Player P;

  // Can store free functions
  P.SetDelegate(LogHealth);

  // Can store lambdas with capture
  int LogCount{0};
  P.SetDelegate([&LogCount](int NewHealth) {  
    std::cout << "Health: " << NewHealth << '\n';
    LogCount++;
  });

  P.TakeDamage(30);
}

When to Use Each

Use raw function pointers when:

  • You only need to store simple function pointers
  • Performance is absolutely critical
  • Memory usage must be minimized

Use std::function when:

  • You need to store lambdas with captures
  • You need to store member functions
  • You want to store different types of callables
  • The flexibility is worth the small overhead

Remember that premature optimization is the root of all evil. Start with std::function for its flexibility, and only switch to raw function pointers if profiling shows it's necessary for your specific use case.

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?
Delegate Performance Impact
How does the performance of delegates compare to direct function calls?
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?
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