我是否以正确的方式剖析(C ++虚函数)

时间:2017-04-03 12:20:26

标签: c++ qt polymorphism profiling

我想放弃虚函数来支持函数指针,所以我做了一些分析,这是怎么做的。

我要做的是决定是否使用虚函数或函数指针(int(* fcnPtr)(int);)来实现多态。

运行时多态性1:

  • 只需使用虚拟功能。

运行时多态性2(我觉得有点快,但设计不好):

  • 创建一个函数指针,如(int(* fcnPtr)(int);)作为成员变量。
  • 现在每个子类都定义了自己的函数指针。
  • 在非虚拟基本函数fct()
  • 中调用函数指针
  • 现在你有一个调用多个函数的直接方法。

这将导致两个调用,一个用于直接方法,然后是函数指针,将在每个子类中重新定义。 即使有两个调用,它仍然比虚拟函数快(120毫秒),对于10 * 1000 * 1000调用,对于1000个子类,我认为这是由于虚函数查找,如果我没有弄错,它在这种情况下,我必须在1000个类之间查找正确的类来调用正确的函数。

我创建了一个基类

void testFct()
{
    int c = 0; c+=10;
}

class Base_Class{
    public:Base_Class(){}
    ~Base_Class(){}
    virtual void v_Fct() __attribute__ ((noinline)){ int c = 0; c+=10; 
    void fct() __attribute__ ((noinline)){ fcnPtr(); }
    void (*fcnPtr)() = testFct;
};

然后我生成了1000个这样的子类。

class Child_Class_0: public Base_Class
{
   public:
   Child_Class_0(){}
   virtual void v_Fct() __attribute__ ((noinline)){ int c = 0; c+=10;}
};

class Child_Class_1: public Base_Class
{
   public:
   Child_Class_1(){}
   virtual void v_Fct() __attribute__ ((noinline)){ int c = 0; c+=10;}
};

我还生成了这样的工厂函数,以便在运行时创建对象:

Base_Class *createObj( int i )
{
    switch ( i ) {
        case 0:
           return new Child_Class_0();
           break;
        case 1:
           return new Child_Class_1();
           break;


        case ..:
        case 999:

}

以下是分析功能:

void profileVirtuals( int classCount , qreal maxCalls )
{
    qreal i = 0;
    QElapsedTimer myTimer;
    myTimer.start();

    /// At this point , the compiler has no idea
    /// which child class to instantiate
    for ( ;i < maxCalls; ++i) {
        int randChild = random( 0 , classCount );
        Base_Class *cc = createObj( randChild );
        if( cc ){
           /// Call virtual function
           cc->v_Fct();
           delete cc;
        }
        /// Make sure we are not missing any calls
        else
            qDebug() << "NULL";
    }
    int elapsed = myTimer.elapsed();
    qDebug() << "VIRTUAL Function Called : " << i << " times.";
    qDebug() << "DONE : " << elapsed;
}

void profileDirects( int classCount , qreal maxCalls )
{
    qreal i = 0;
    QElapsedTimer myTimer;
    myTimer.start();

   /// At this point , the compiler has no idea
   /// which child class to instantiate
   for ( ;i < maxCalls; ++i) {
       int randChild = random( 0 , classCount );
       Base_Class *cc = createObj( randChild );
      if( cc ){
           /// Call direct function
            cc->fct();
            delete cc;
      }
      /// Make sure we are not missing any calls
      else
          qDebug() << "NULL";
    }
    int elapsed = myTimer.elapsed();
    qDebug() << "DIRECT Function Called : " << i << " times.";
    qDebug() << "DONE : " << elapsed;
}

以下是主要功能,我将虚拟功能和直接功能分别称为10 * 1000 * 1000次

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int classCount = 1000;
    qreal maxCalls = 10 * 1000 * 1000;
    profileVirtuals( classCount ,  maxCalls );
    profileDirects( classCount , maxCalls );
    return a.exec();

}

我得到的是10 * 1000 * 1000的电话,大约120毫秒的差异(当然直接电话更快)。毕竟没有那么显着的差异

代码在Qt框架中,但可以很容易地理解为标准C ++。 如果有什么不清楚的地方,关于我刚刚做了什么,或者试图做什么,我会更新问题。

结论:

  • 如果100个子类中的子类较少,则多态性1比多态性2快。

  • 多态性2比多态性1快,如果有很多子类,超过1000个子类,则vTable查找会降低它的速度。

0 个答案:

没有答案