2012-10-06 195 views
1

虚拟性可以有一个双顶置:非虚拟成员的虚拟和继承成本?

  • 内存
  • 运行速度

由于内存开销(因为vptr的和虚函数表的),我使用一些CRTP技术有一种静态虚拟性,当我需要非常高的内存优化。

但我想知道虚拟性的运行速度,非虚成员的费用:

#include <iostream> 

class Base 
{ 
    public: 
     Base() {;} 
     virtual ~Base() {;} 

    public: 
     virtual void f1() {std::cout<<"f1 : Base"<<std::endl; /* FUNCTION BODY */} 
     void f2() {std::cout<<"f2 : Base"<<std::endl; /* FUNCTION BODY */} 
     void f3() {f1();} 
}; 

class Derived : public Base 
{ 
    public: 
     Derived() {;} 
     virtual ~Derived() {;} 

    public: 
     virtual void f1() {std::cout<<"f1 : Derived"<<std::endl; /* FUNCTION BODY */} 
}; 

和主:

int main() 
{ 
    Base b; 
    Derived d; 
    Base* ptr = new Derived(); 

    std::cout<<std::endl; 
    b.f1(); // 1a 
    b.f2(); // 1b 
    b.f3(); // 1c 
    std::cout<<std::endl; 
    d.f1(); // 2a 
    d.f2(); // 2b 
    d.f3(); // 2c 
    std::cout<<std::endl; 
    ptr->f1(); // 3a 
    ptr->f2(); // 3b 
    ptr->f3(); // 3c 
    std::cout<<std::endl; 

    return 0; 
} 

对于每一种情况:1A,1B ... 3c,与Base和Derived是两个完全独立的类没有继承的情况相比,由于继承+虚拟性,我在哪里有运行时间开销(增加了执行时间)?

特别是,f2函数有没有运行时开销?

注意:std::cout只是一个例子。 /* FUNCTION BODY */可以是1k行代码...

+4

“对于每一种情况...其中我有更多的CPU指令吗?“你的编译器会产生一个汇编列表,如果[礼貌地问它](http://stackoverflow.com/questions/840321/how-can-i-see-the-assembly-code-for-a-c-program)。 –

+1

只计算CPU指令的数量将提供一个错误度量。循环展开本质上增加了指令的数量,但“矛盾地”增加了运行速度。使用cout而不是printf的开销比任何对vtable的检查和随后的重定向要慢几个数量级。 (cout作为例子 - 我明白这不是问题的本质) – enhzflep

+1

@enhzflep:我编辑了我的问题,考虑到你的言论。 – Vincent

回答

3

为什么不只是时间呢?这是一个完全平凡的工作..

首先,一些成果

100 million instances of b.f1() = 0.774852 secs. 
100 million instances of b.f2() = 0.78162 secs. 
100 million instances of b.f3() = 1.85278 secs. 

100 million instances of d.f1() = 0.773115 secs. 
100 million instances of d.f2() = 0.886528 secs. 
100 million instances of d.f3() = 1.88562 secs. 

100 million instances of ptr->f1() = 1.02043 secs. 
100 million instances of ptr->f2() = 0.778072 secs. 
100 million instances of ptr->f3() = 1.72503 secs. 

假设的win32,(QueryPerformanceXXXXX & LARGE_INTEGER),你可以使用以下内容:

#include <windows.h> 
#include <iostream> 
using namespace std; 

class Base 
{ 
    public: 
     Base() {;} 
     virtual ~Base() {;} 

    public: 
     virtual void f1() {};//std::cout<<"f1 : Base"<<std::endl; /* FUNCTION BODY */} 
     void f2() {}; //std::cout<<"f2 : Base"<<std::endl; /* FUNCTION BODY */} 
     void f3() {f1();} 
}; 

class Derived : public Base 
{ 
    public: 
     Derived() {;} 
     virtual ~Derived() {;} 

    public: 
     virtual void f1() {};//std::cout<<"f1 : Derived"<<std::endl; /* FUNCTION BODY */} 
}; 


LARGE_INTEGER clockFreq; 

LARGE_INTEGER getTicks() 
{ 
    LARGE_INTEGER result; 
    QueryPerformanceCounter(&result); 
    return result; 
} 

double elapsedSecs(LARGE_INTEGER tStart, LARGE_INTEGER tEnd) 
{ 
    long ticksElapsed = tEnd.QuadPart - tStart.QuadPart; 
    double timePeriod = (double)ticksElapsed/(double)clockFreq.QuadPart; 
    return timePeriod; 
} 


int main() 
{ 
    LARGE_INTEGER tStart, tEnd; 
    Base b; 
    Derived d; 
    long i, max=100000000; 

    Base* ptr = new Derived(); 

    // find how fast the clock ticks 
    QueryPerformanceFrequency(&clockFreq); 


/*==================================================================================================== 
    Test for access using b 
    b.f1() 
    b.f2() 
    b.f3() 
====================================================================================================*/ 
    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     b.f1(); // 1a 
    } 
    tEnd = getTicks(); 
    double elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of b.f1() = " << elapsed << " secs." << endl; 


    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     b.f2(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of b.f2() = " << elapsed << " secs." << endl; 

    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     b.f3(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of b.f3() = " << elapsed << " secs." << endl; 


/*==================================================================================================== 
    Test for access using d 
    d.f1() 
    d.f2() 
    d.f3() 
====================================================================================================*/ 
    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     d.f1(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of d.f1() = " << elapsed << " secs." << endl; 


    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     d.f2(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of d.f2() = " << elapsed << " secs." << endl; 

    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     d.f3(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of d.f3() = " << elapsed << " secs." << endl; 

/*==================================================================================================== 
    Test for access using ptr 
    ptr->f1() 
    ptr->f2() 
    ptr->f3() 
====================================================================================================*/ 
    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     ptr->f1(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of ptr->f1() = " << elapsed << " secs." << endl; 


    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     ptr->f2(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of ptr->f2() = " << elapsed << " secs." << endl; 

    std::cout<<std::endl; 
    tStart = getTicks(); 
    for (i=0; i<max; i++) 
    { 
     ptr->f3(); // 1a 
    } 
    tEnd = getTicks(); 
    elapsed = elapsedSecs(tStart, tEnd); 
    cout << "100 million instances of ptr->f3() = " << elapsed << " secs." << endl; 

    return 0; 
}