众所周知的解决方案,用于避免dynamic_cast的缓慢
Well-known solution for avoiding the slowness of dynamic_cast?
我需要运行时多态性,所以我使用了dynamic_cast
.
但是现在我有两个问题 - dynamic_cast
非常慢!(向下滚动查看基准测试。
长话短说,我最终以这种方式解决了问题,使用 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
}
但我肯定不是第一个遇到这个问题的人,所以我认为可能值得一问:
与其提出这样的自制解决方案,不如将来可以使用一个众所周知的模式/库来解决此问题?
<小时 />示例基准测试
要了解我在说什么,请尝试下面的代码 - dynamic_cast
比我的机器上的仅virtual
调用慢大约 15 倍(110 毫秒,而下面的代码为 1620 毫秒(:
#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 毫秒的运行时间——所以虚拟调用只比静态调用慢 ~25%!
dynamic_cast
的大多数用法都可以用双重调度(又名访客模式(代替。这相当于两个虚拟调用,根据您的基准测试,这仍然比 dynamic_cast
快 7.5 倍。
您可能对这个常量时间实现感兴趣:http://www.stroustrup.com/isorc2008.pdf
另请注意,许多上行转换在特定约束下可能会得到简化 - 例如,如果您不使用多重继承,仅使用浅继承,或者以其他方式保证类型没有共同的祖先,则某些评估可能会短路,并且不需要执行详尽的评估(如 dynamic_cast
提供(。
像往常一样,针对给定用例和实际类层次结构,根据供应商的实现来分析您的实现。
相关文章:
- 缓慢提升ASIO
- 在成员dynamic_bitset上使用 boost::from_block_range 时出错,但在本地dynamic
- 使用istringstearm和get行缓慢读取文件
- 当键值是 std 向量时,为什么使用 at in C++ 访问映射值如此缓慢?
- 基于Q3DScatter的自定义图表,QCustom3DItem运行缓慢
- C++类中的二维"dynamic"数组?
- QLibrary 函数在第一次调用时工作缓慢
- QQuickPaintedItem 使用 QPainter 缓慢更新
- Qt,操作缓慢时不要冻结GUI输入元素
- 为什么基于Dear ImGui的渲染器如此缓慢
- protobuf in C++ with dynamic binding for google::protobuf::M
- 与地图C++相比,无序地图运行异常缓慢
- 在图形场景Qt中右键单击Contex菜单时响应缓慢
- 警告的原因是什么:"when type is in parentheses, array cannot have dynamic size"?
- 为什么这个局部的 recrutic C++ lambda 如此缓慢?
- 内存在 32 位嵌入式平台上运行缓慢
- 当对象在屏幕空间中较小时,OpenGL 更新缓慢
- 如何修复macOS线程互斥锁性能缓慢的问题?
- CUDA 错误:"dynamic initialization is not supported for __device__, __constant__ and __shared__ variabl
- 如何修复'The procedure entry point SDL_RWclose could not be located in the dynamic link library'