【问题标题】:Cost of virtuality and inheritance for non virtual members?非虚拟成员的虚拟成本和继承?
【发布时间】:2012-09-27 05:23:55
【问题描述】:

虚拟可能有双重开销:

  • 内存(由于 vptr 和 vtable)
  • 运行时速度

由于内存开销的原因,当我需要非常高的内存优化时,我会使用一些 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行代码...

【问题讨论】:

  • "对于每种情况...我在哪里有...更多 CPU 指令?"如果您ask it politely,您的编译器将生成一个汇编列表。
  • 只计算 CPU 指令的数量会提供一个错误的指标。循环展开本质上增加了指令的数量,但“矛盾的是”它增加了运行时速度。使用 cout 而不是 printf 的开销比任何检查 vtable 和随后的重定向要慢几个数量级。 (以 cout 为例 - 我理解这不是问题的本质)
  • @enhzflep :考虑到您的评论,我编辑了我的问题。
  • 看这里:stackoverflow.com/questions/6749621/… 可能更合适的东西..

标签: c++ optimization inheritance virtual


【解决方案1】:

为什么不计时呢?这是一个完全微不足道的练习..

首先,一些结果

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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    • 2023-03-23
    • 2016-05-20
    相关资源
    最近更新 更多