Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving function pointer+arguments for later use

Tags:

c++

c++11

I have this problem where a C++ function pointer is saved, together with a set of arguments to call it on, such that it can be called later. The calling code is unaware of the type and arguments of the functions. Saving and calling function pointers and arguments is extremely performance critical in my application. The interface should look something like this:

void func( int a, char * b );
call_this_later( func, 5, "abc" );

A straightforward solution is to put all of this information in a functor, requiring a different typedef per called function. C++11 would allow me to do that using a variadic template, so that is ok.

Since the type of the functor is not known at the point of call, it seems necessary to create a virtual base class for these functors and to invoke the functors using virtual function calls. The performance overhead of virtual function calls + heap allocation is too high (I am pushing the boundaries of implementing this idiom with as few assembly instructions as possible). So I need a different solution.

Any ideas?

like image 481
Hans Avatar asked Feb 07 '11 20:02

Hans


3 Answers

You could do this with a lambda expression which captures the types.

template <typename Func, typename Arg1, typename Arg2>
std::function<void(void)> call_this_later(Func f, Arg1 a1, Arg2 a2) {
    return [=]() { f(a1, a2); }; // Capture arguments by value
}

A few things to note:

  1. I don't think you can use perfect forwarding here since you have to capture the arguments
  2. Since C++ is not garbage collected, if the arguments are pointers they may point to something that isn't alive later on. For example if your argument is const char* then it's OK if you use it with a string literal but not if you pass someStdString.c_str() and the string is going to die any-time soon.
  3. I gave the example with two arguments, if your compiler supports variadic templates you can use those otherwise just create an overload for each number of arguments.
like image 109
Motti Avatar answered Oct 16 '22 22:10

Motti


What about a solution using boost::function / boost::bind:

void func( int a, char * b );

boost::function<void ()> my_proc = 
    boost::bind(&func, 5, "abc");

// then later...

my_proc(); // calls func(5, "abc");
like image 3
fbrereto Avatar answered Oct 17 '22 00:10

fbrereto


You're going to need a custom allocator to match your allocation pattern. Alternatively, use compile-time polymorphism to pass the type of the functor in to the call site.

like image 2
Puppy Avatar answered Oct 16 '22 23:10

Puppy