Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the cost of using a pointer to member function vs. a switch?

I have the following situation:


class A
{
public:
    A(int whichFoo);
    int foo1();
    int foo2();
    int foo3();
    int callFoo(); // cals one of the foo's depending on the value of whichFoo
};

In my current implementation I save the value of whichFoo in a data member in the constructor and use a switch in callFoo() to decide which of the foo's to call. Alternatively, I can use a switch in the constructor to save a pointer to the right fooN() to be called in callFoo().

My question is which way is more efficient if an object of class A is only constructed once, while callFoo() is called a very large number of times. So in the first case we have multiple executions of a switch statement, while in the second there is only one switch, and multiple calls of a member function using the pointer to it. I know that calling a member function using a pointer is slower than just calling it directly. Does anybody know if this overhead is more or less than the cost of a switch?

Clarification: I realize that you never really know which approach gives better performance until you try it and time it. However, in this case I already have approach 1 implemented, and I wanted to find out if approach 2 can be more efficient at least in principle. It appears that it can be, and now it makes sense for me to bother to implement it and try it.

Oh, and I also like approach 2 better for aesthetic reasons. I guess I am looking for a justification to implement it. :)

like image 417
Dima Avatar asked Sep 22 '08 04:09

Dima


People also ask

What is the advantage of using function pointers?

1) Unlike normal pointers, a function pointer points to code, not data. Typically a function pointer stores the start of executable code. 2) Unlike normal pointers, we do not allocate de-allocate memory using function pointers. 3) A function's name can also be used to get functions' address.

Can we create a pointer to a member function?

You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.

What is the difference between pointer and function?

Function Pointers are pointers(like variable pointers) which point to the address of a function. They actually calling the underlying function when you dereference them like a function call does. The main advantage of a function pointer is that you can pass it to another function as a parameter for example ...

Is a pointer that points to the object that invokes a member function?

Which is the pointer which denotes the object calling the member function? Explanation: The pointer which denotes the object calling the member function is known as this pointer. The this pointer is usually used when there are members in the function with same name as those of the class members.


2 Answers

How sure are you that calling a member function via a pointer is slower than just calling it directly? Can you measure the difference?

In general, you should not rely on your intuition when making performance evaluations. Sit down with your compiler and a timing function, and actually measure the different choices. You may be surprised!

More info: There is an excellent article Member Function Pointers and the Fastest Possible C++ Delegates which goes into very deep detail about the implementation of member function pointers.

like image 73
Greg Hewgill Avatar answered Sep 24 '22 16:09

Greg Hewgill


You can write this:

class Foo {
public:
  Foo() {
    calls[0] = &Foo::call0;
    calls[1] = &Foo::call1;
    calls[2] = &Foo::call2;
    calls[3] = &Foo::call3;
  }
  void call(int number, int arg) {
    assert(number < 4);
    (this->*(calls[number]))(arg);
  }
  void call0(int arg) {
    cout<<"call0("<<arg<<")\n";
  }
  void call1(int arg) {
    cout<<"call1("<<arg<<")\n";
  }
  void call2(int arg) {
    cout<<"call2("<<arg<<")\n";
  }
  void call3(int arg) {
    cout<<"call3("<<arg<<")\n";
  }
private:
  FooCall calls[4];
};

The computation of the actual function pointer is linear and fast:

  (this->*(calls[number]))(arg);
004142E7  mov         esi,esp 
004142E9  mov         eax,dword ptr [arg] 
004142EC  push        eax  
004142ED  mov         edx,dword ptr [number] 
004142F0  mov         eax,dword ptr [this] 
004142F3  mov         ecx,dword ptr [this] 
004142F6  mov         edx,dword ptr [eax+edx*4] 
004142F9  call        edx 

Note that you don't even have to fix the actual function number in the constructor.

I've compared this code to the asm generated by a switch. The switch version doesn't provide any performance increase.

like image 37
cos Avatar answered Sep 22 '22 16:09

cos