Click here to Skip to main content
Click here to Skip to main content

Delegates: C++11 vs. Impossibly Fast - A Quick and Dirty Comparison

, 4 Jul 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
A quick comparison of the C++11 lambda/delegate approach vs. Sergey Ryazanov's 'Impossibly Fast Delegates.'
This is an old version of the currently published article.


The following is for you who are curious about how Sergey Ryazanov's Impossibly Fast C++ Delegates compares to a C++11 lambda/function pointer approach. This is not meant to put one down, nor is it even close to comprehensive, which is why 'quick and dirty' is included in the title.

As a background my Windows API wrapper incorporated Ryazanov's delegates to implement the member function callbacks. My curiosity got the better of me, and I wanted to play around with the new C++11 lambda functions and see how delegates created with them compared to the existing approach in both usage and performance.


In order to create a usable callback in DWinLib 3.01 it had to have a function signature of:

void DwlWinObjectDerivedClass::someFunction(DwlWinObject * usableObjectPointer) { ... }

The reason for only allowing one specific signature had to do with historical items including being influenced by Borland Builder's syntax, and the fact that Builder 4.0 couldn't compile all of Ryazanov's code, so this aspect was hard coded.

In C++11 using lamdba functions, it is fairly easy to overcome this limitation. But because this is a quick and dirty comparison, such won't be done. The existing method will be recreated in Microsoft Visual Studio Express 2012.

As expected, sementic differences exist between the two methods. Using the same function signature for both approaches, in the existing DWinLib solution a delegate had to be created like so:

DwlDelegate del1(CreateDelegate(Controller, delegate1, this, this));

Then that delegate needed to be somehow stored in the containing object:

DwlDelegate delegateC = del1;

And finally it was executed from within the containing object as a response to some event:


Not too bad, all things considered. Now let's look at the new lambda/callback solution. In it the containing class contains a std::function object rather than a DwlDelegate:

std::function<void (DwlWinObject*)> callbackFuncC;

Then the function is registered in the containing class by calling:

containingClass.setCallback( [&] (DwlWinObject*) { callbackFunc(this); } );

(Thanks go to Alex Allain's Lambda Functions in C++11 - the Definitive Guide for illuminating the correct syntax.)

In this, the containing class defines 'setCallback' like so:

void setCallback(std::function<void (DwlWinObject*)> func) {
   callbackFuncC = func;

Also, in order to compare apples to apples, we must add a DwlWinObject pointer to the containing class and have the caller register the appropriate value. See the code for the details. It is worth noting that we are not directly comparing apples to apples at this point in the release code because the subsequent calls to dwlWinObject are probably optimized out by the compiler for the lambda approach. In the real world the DwlWinObject pointer is seldom needed, and it should be possible to eliminate this in most cases.

And finally, the containing class executes the callback via:



On my computer, the lambda/callback approach took about four times as long as the 'Impossibly Fast Delegates' technique in release mode. Even though this not incredibly impressive as far as performance, I will probably use this approach in the next iteration of DWinLib because of the ease in which function signatures can be changed.


  • As stated earlier, this is simply a quick and dirty comparison.
  • The lambda/callback routine is easier to modify variable function signatures than the hard-coded approach used in DWinLib, although Ryazanov's full 'Impossibly Fast Delegates' code can be used with variable signatures if desired.
  • The code to compare with Mikhail Semenov's Implementation of Delegates in C++11 has been included in the source, but has been commented out because it won't compile in Visual Studio Express 2012. Having never been tested, I cannot say I modified it correctly, or how it compares to the other techniques. If you get it to work on another compiler, feel free to post your times, and any corrections, in the comments.
  • Even though the C++11 method is about 400% slower than the Impossibly Fast Delegate one, the end cost is still acceptable for my usage. If this was used in an inner loop of a high performance routine, such wouldn't be the case.
  • The main reason for going with the lambda/delegate solution is the awkwardness of the constructing method when using the Impossibly Fast Delegates. Without macro help, the existing method requires remembering: create<ClassName, &ClassName::FunctionName>(Instance, WinObjectPtr). Ungh! Although lambdas aren't much better, they are still an improvement.

The Code Listing

The following is the complete code used for my test. Feel free to modify it however you wish.

#include <functional>
#include <ctime>
#include <iostream>

//Utility class for the timing...
class Timer {
      std::clock_t begC;
      std::clock_t avgTotC;
      std::clock_t diffC;
      int numTimesC;      
      Timer() : avgTotC(0), numTimesC(0) { }

      void start() { begC = std::clock(); }

      std::clock_t stop() {
         diffC = std::clock() - begC;
         avgTotC = avgTotC + diffC;
         return diffC;

      std::clock_t getAvg() {
         if (numTimesC == 0) return 0;
         return avgTotC/numTimesC;

      void reset() {
         numTimesC = 0;
         avgTotC = 0;

      std::clock_t getLapTime() { return std::clock() - begC; }

//The full DwlWinObject incorporates more, but this is just for testing...
class DwlWinObject {

//The following Delegate is derived from Sergey Ryazanov's CodeProject article:
//First, a useful define for simplifying the call to DwlDelegate::create:
#define CreateDelegate(ClassName, FunctionName, Instance, WinObjectPtr) \
            DwlDelegate::create<ClassName, &ClassName::FunctionName>(Instance, WinObjectPtr)

//Example usage:
//          CreateDelegate(WinMainO, newWindow, gWinMain, parentC);
//This replaces the more awkward:
//          DwlDelegate::create<WinMainO, &WinMainO::newWindow>(gWinMain, parentC));

class DwlDelegate {
      typedef void (*stub_type)(void* object_ptr, DwlWinObject * arg);
      stub_type stub_ptrC;

      void * object_ptrC;
      DwlWinObject * argC;

      template <class T, void (T::*TMethod)(DwlWinObject*)>
      static void method_stub(void* object_ptr, DwlWinObject * a1) {
         T* p = static_cast<T*>(object_ptr);
         return (p->*TMethod)(a1);
      DwlDelegate() : object_ptrC(0), argC(0) , stub_ptrC(0) { }

      template <class T, void (T::*Method)(DwlWinObject*)>
      static DwlDelegate create(T* object_ptr, DwlWinObject * arg) {
         DwlDelegate d;
         d.stub_ptrC = &method_stub<T, Method>;
         d.object_ptrC = object_ptr;
         d.argC = arg;
         return d;

      void operator()() const {
         return (*stub_ptrC)(object_ptrC, argC);

      void object(DwlWinObject * p) { argC = p; }

/*//Mikhail Semenov's approach:
template <class F>
F* create_delegate(F* f) {
   return f;

template <class T, class R, class ... P>\
struct _mem_delegate ## _NAME {\
   T* classC;\
   R  (T::*functionC)(P ...) _Q;\
   _mem_delegate ## _NAME(T* t, R  (T::*f)(P ...) _Q):classC(t),functionC(f) {}\
   R operator()(P ... p) _Q {\
      return (classC->*functionC)(std::forward<P>(p) ...);\
template <class T, class R, class ... P>\
   _mem_delegate ## _NAME<T,R,P ...> create_delegate(T* t, R (T::*f)(P ...) _Q) {\
   _mem_delegate ##_NAME<T,R,P ...> d(t,f);\
   return d;\

_MEM_DELEGATES(const volatile,W)*/

class DwlButton : public DwlWinObject {
      DwlWinObject * ptrC;
      std::function<void (DwlWinObject*)> callbackFunc1C;
      std::function<void (DwlWinObject*)> callbackFunc2C;
      DwlDelegate buttonDelegateC;
      void dwlWinObject(DwlWinObject * p) { ptrC = p; }

      void setCallback1(std::function<void (DwlWinObject*)> func) {
         callbackFunc1C = func;

      void doCallback1() {

      void setCallback2(std::function<void (DwlWinObject*)> func) {
         callbackFunc2C = func;

      void doCallback2() {

      void setDelegate(DwlDelegate del) {
         buttonDelegateC = del;

      void doDelegate() {

class Controller : public DwlWinObject {
      DwlButton buttonC;
      int yC;
      void delegate1(DwlWinObject * obj) {

      void delegate2(DwlWinObject * obj) {

      void delegate3(DwlWinObject * obj) {

      void callbackFunc1(DwlWinObject * obj) {

      void callbackFunc2(DwlWinObject * obj) {

      void callbackFunc3(DwlWinObject * obj) {

      auto del1(DwlWinObject * obj)->void {

      void del2(DwlWinObject * obj) {

      void del3(DwlWinObject * obj) {

      Controller() : yC(0) {
         Timer timerC;
         int numIterations = 100000000;

         //First, test the new lambda function delegate approach:
         for (int i=0; i<numIterations; ++i) {
            //The reason for sending 'this' is simply to try comparing apples to apples.
            //We don't need it for anything, but the method in DWinLib incorporated a
            //DwlWinObject * as a type of user variable to do with as wished, so it is
            //incorporated here to be comparable even if not used.
            buttonC.setCallback1( [&] (DwlWinObject*) { callbackFunc1(this); } );
            //if the callback function was simply a standalone function, the call would be:
            //Doing it this way, we must also set the DwlWinObject pointer manually:
            buttonC.setCallback1( [&] (DwlWinObject*) { callbackFunc2(this); } );
            buttonC.setCallback1( [&] (DwlWinObject*) { callbackFunc3(this); } );
         time_t time = timerC.stop();
         std::cout << "Lambda approach:" << std::endl;
         std::cout << "time: " << time << "  y: " << yC << std::endl;

         /*//Now do the delegates as in Mikhail Semenov's "Implementation of Delegates in C++11"
         auto d1 = create_delegate(this, &del1(DwlWinObject*));
         auto d2 = create_delegate(this, &del2(DwlWinObject*));
         auto d3 = create_delegate(this, &del3(DwlWinObject*));
         for (int i=0; i<numIterations; ++i) {
         time = timerC.stop();
         std::cout << "Semenov's implementation:" << std::endl;
         std::cout << "time: " << time <<  "  y: " << yC << std::endl;*/
         for (int i=0; i<numIterations; ++i) {
            DwlDelegate del1(CreateDelegate(Controller, delegate1, this, this));
            DwlDelegate del2(CreateDelegate(Controller, delegate2, this, this));
            DwlDelegate del3(CreateDelegate(Controller, delegate3, this, this));
         time = timerC.stop();
         std::cout << "Impossibly Fast" << std::endl;
         std::cout << "time: " << time <<  "  y: " << yC << std::endl;
         std::cout << "Press a key and 'Enter' to quit ";
         std::cin >> time; //Total junk way to do this, but good enough for testing
         numIterations++;  //Just to put a breakpoint on for non-cin approach

void main() {
   Controller control;


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

David O'Neil
Software Developer
United States United States
I am the author of Laughing at the Devil: One Man’s Religious Discoveries. For those who are “ready to look at the world - religion, science, spirituality - differently,” LATD is the book to turn to.
In about 1994 I began studying and documenting the astronomy of our ancestors. A hint lead to many years of partial understanding, before a profound breakthrough occurred and some old myths finally made sense.
The greatest of my discoveries is the celestial observations behind the biblical tale of Samson, which was created 3,000 years ago. That find casts a profound new light on the roots of Western religion, as well as the foundation of modern science. To learn more, visit my website.
Trained as a mechanical engineer, I learned C++ programming on my own in order to create a MIDI program. I am delighted to say I also succeeded in that goal. Happy coding, everybody!

Comments and Discussions

Discussions posted for the Published version of this article. Posting a message here will take you to the publicly available article in order to continue your conversation in public.
GeneralMy vote of 5 Pinmemberarashmd4-Jul-13 11:20 
GeneralRe: My vote of 5 PinmemberDavid O'Neil4-Jul-13 12:23 
GeneralRe: My vote of 5 Pinmemberarashmd4-Jul-13 19:37 
GeneralRe: My vote of 5 PinmemberDavid O'Neil4-Jul-13 21:33 
GeneralRe: My vote of 5 Pinmemberarashmd4-Jul-13 22:04 
GeneralRe: My vote of 5 PinmemberDavid O'Neil6-Jul-13 10:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141015.1 | Last Updated 4 Jul 2013
Article Copyright 2013 by David O'Neil
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid