使用成员函数指针与交换机的成本是多少?

Dim*_*ima 12 c++ function-pointers

我有以下情况:


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
};
Run Code Online (Sandbox Code Playgroud)

在我当前的实现中,我保存whichFoo构造函数中的数据成员的值,并使用switchin callFoo()来决定要调用哪个foo.或者,我可以switch在构造函数中使用a 来保存指向fooN()要调用的权限的指针callFoo().

我的问题是,如果A类的一个对象只构造一次,那么哪种方式更有效,而callFoo()被称为非常多次.所以在第一种情况下我们有多个switch语句的执行,而在第二种情况下只有一个开关,并且使用指向它的指针多次调用成员函数.我知道使用指针调用成员函数比直接调用它要慢.有人知道这个开销是多少还是少于一个switch

澄清:我意识到你从来没有真正知道哪种方法可以提供更好的性能,直到你尝试并计时.但是,在这种情况下,我已经实施了方法1,并且我想知道方法2是否可以至少在原则上更有效.它似乎可以,现在我有理由去实现它并尝试它.

哦,我也喜欢方法2更好的审美原因.我想我正在寻找实现它的理由.:)

Gre*_*ill 11

你是否确定通过指针调用成员函数比直接调用它更慢?你能衡量差异吗?

一般来说,在进行绩效评估时,不应该依赖自己的直觉.坐下来使用您的编译器和计时功能,并实际测量不同的选择.你可能会感到惊讶!

更多信息:有一篇优秀的文章成员函数指针和最快可能的C++代表,它们详细介绍了成员函数指针的实现.

  • 指向虚拟成员函数的指针实际上可能是最一般情况下的结构,但指向常规成员函数的指针只是其地址.在简单的单继承情况下,指向虚拟成员函数的指针只需要是vtable的偏移量. (2认同)

cos*_*cos 8

你可以这样写:

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];
};
Run Code Online (Sandbox Code Playgroud)

实际函数指针的计算是线性和快速的:

  (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 
Run Code Online (Sandbox Code Playgroud)

请注意,您甚至不必在构造函数中修复实际的函数编号.

我已将此代码与a生成的asm进行了比较switch.该switch版本不提供任何性能提升.