知名的解决方案,以避免dynamic_cast的慢? [英] Well-known solution for avoiding the slowness of dynamic_cast?
问题描述
我需要运行时多态性,所以我使用 dynamic_cast
。
但现在我有两个问题 - dynamic_cast
非常慢! (向下滚动以作为基准。)
I needed run-time polymorphism, so I used dynamic_cast
.
But now I had two problems -- dynamic_cast
was extremely slow! (Scroll down for benchmark.)
很长的故事,我最终以这种方式解决问题,使用 static_cast
:
Long story short, I ended up solving the problem this way, using static_cast
:
struct Base
{
virtual ~Base() { }
virtual int type_id() const = 0;
template<class T>
T *as()
{ return this->type_id() == T::ID ? static_cast<T *>(this) : 0; }
template<class T>
T const *as() const
{ return this->type_id() == T::ID ? static_cast<T const *>(this) : 0; }
};
struct Derived : public Base
{
enum { ID = __COUNTER__ }; // warning: can cause ABI incompatibility
int type_id() const { return ID; }
};
int main()
{
Base const &value = Derived();
Derived const *p = value.as<Derived>(); // "static" dynamic_cast
}
但我肯定不是第一个人遇到这个问题,所以我认为这可能值得问:
But I'm surely not the first person to run into this problem, so I thought it might be worth asking:
不是想出一个自制的解决方案像这样,有一个众所周知的模式/
Instead of coming up with a home-baked solution like this, is there a well-known pattern/library I can use for solving this problem in the future?
要感觉我在说什么,请尝试下面的代码 - dynamic_cast
大约是 15次比我在我的机器上的虚拟
调用(110 ms。对于1620 ms。下面的代码):
To get a feel for what I'm talking about, try the code below -- dynamic_cast
was approximately 15 times slower than a mere virtual
call on my machine (110 ms. against 1620 ms. with the code below):
#include <cstdio>
#include <ctime>
struct Base { virtual unsigned vcalc(unsigned i) const { return i * i + 1; } };
struct Derived1 : public Base
{ unsigned vcalc(unsigned i) const { return i * i + 2; } };
struct Derived2 : public Derived1
{ unsigned vcalc(unsigned i) const { return i * i + 3; } };
int main()
{
Base const &foo = Derived2();
size_t const COUNT = 50000000;
{
clock_t start = clock();
unsigned n = 0;
for (size_t i = 0; i < COUNT; i++)
n = foo.vcalc(n);
printf("virtual call: %d ms (result: %u)\n",
(int)((clock() - start) * 1000 / CLOCKS_PER_SEC), n);
fflush(stdout);
}
{
clock_t start = clock();
unsigned n = 0;
for (size_t i = 0; i < COUNT; i++)
n = dynamic_cast<Derived1 const &>(foo).vcalc(n);
printf("virtual call after dynamic_cast: %d ms (result: %u)\n",
(int)((clock() - start) * 1000 / CLOCKS_PER_SEC), n);
fflush(stdout);
}
return 0;
}
当我简单地删除 virtual
并将 dynamic_cast
更改为 static_cast
,我得到了79 ms的运行时间 - 只是比静态调用慢约25%!
When I simply remove the word virtual
and change dynamic_cast
to static_cast
, I get a 79 ms running time -- so a virtual call is only slower than a static call by ~25%!
推荐答案
dynamic_cast
可以替换为double dispatch(又称为访问者模式)。这将相当于两个虚拟调用,这是你的基准仍然是 dynamic_cast
的7.5倍。
Most uses of dynamic_cast
can be replaced with double dispatch (aka. visitor pattern). That would amount to two virtual calls, which by your benchmark is still 7.5 times faster than dynamic_cast
.
这篇关于知名的解决方案,以避免dynamic_cast的慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!