哪个表现得更快?使用N个派生类型进行vtable查找,还是使用N个元素进行std :: map查找?

时间:2014-11-09 01:09:25

标签: c++ performance map vtable

#include <iostream>
#include <map>
#include <ctime>

struct Base { virtual void foo() {} };
struct A : Base { void foo() {} };
struct B : Base { void foo() {} };
struct C : Base { void foo() {} };

A* protoA = new A;  B* protoB = new B;  C* protoC = new C;

enum Tag {a, b, c};

std::map<Tag, Base*> protoMap = { {a, protoA}, {b, protoB}, {c, protoC} };

void goo(Base* base) {base->foo();}

void hoo(Tag tag) {protoMap[tag]->foo();}

struct Timer {
    const std::clock_t begin;
    Timer() : begin (std::clock()) {}
    ~Timer() {
        const std::clock_t end = std::clock();
        std::cout << double (end - begin) / CLOCKS_PER_SEC << " seconds." << std::endl;
    };
};

int main() {
    const long N = 10000000;
    {
        Timer timer;
        for (int i = 0; i < N; i++)
            goo(new C);  // using vtable
    }  // 0.445 seconds.
    {
        Timer timer;
        for (int i = 0; i < N; i++)
            hoo(c);  // using map
    }  // 0.605 seconds.
    std::cin.get();
}

但是我的测试只使用了三个派生类,而且我不知道如何定义数千个派生类来正确地进行基准测试。有没有人知道答案,所以我不必考虑如何运行更好的测试?

我处于可以轻松使用地图的情况,但是尝试使用vtable查找来提高性能需要重新设计我已经拥有的很多东西(向类中添加新的数据成员) ,定义一个新的构造函数,实现一个访问者模式等...)。

1 个答案:

答案 0 :(得分:0)

毫无疑问,最快的方法是vtable。

实验:

您必须在类似条件下运行基准测试。为vtable基准测试的每次调用分配一个新元素是不合理的,但是不要在map方法中分配任何东西。

我使用vtable方法运行测试,使用指向已分配元素的指针。我得到16毫秒的vtable和78毫秒的地图方法。

如果你想进一步比较第1000个衍生物,你必须使用递归模板。

结果说明:

vtable查找通常使用对象的fixed offset in the vtable,而不是搜索。所以即使有1000个推导,你也会在O(1)中有一个恒定的反应时间。

地图需要对密钥执行昂贵的搜索操作,即O(log(n))。

补充说明:

您建议的地图实现在reallife中不起作用,因为您总是调用ONE SINGLE预定对象的成员函数:您存储在地图中的对象。虚拟功能将适用于该系列的任何对象。