虚转换或类型转换

virtual or type casting

本文关键字:类型转换 转换      更新时间:2023-10-16

我有一个问题。我试图创建代码来更新我的游戏,但我已经进入了一个"困境"。我不想使用virtual,唯一的原因是我交谈过的每个人(在论坛,聊天,朋友)都说virtual使代码非常慢,所以我做了一个研究,发现它从vtable中查找会使性能降低近一半。因此,我将它用于不需要每帧更新的任务。一切都很好,直到我得到更新/渲染功能。然后我开始想找个变通办法。我有了一个想法,但在实现它之前,我想先问一下有这个想法的人。

我的游戏引擎是由事件驱动的。我可以在子系统(图形,ui,脚本)之间使用事件发送任何类型的数据。所以,我正在考虑每帧发送一个事件"renderScene"。听起来不错,但有个问题。事件处理程序的结构不是很好,我现在真的不想改进它,因为它做得很好,我的目标是完成我的游戏,而不是修复引擎,永远不会完成它(发生在我身上,所以不想再回去了)。

我的事件处理程序有一个函数,它将事件注册到函数(我调用处理程序)。但这个函数的问题是,我需要做函数绑定之类的来注册成员函数。所以,我找到了一个解决方法——我创建一个静态函数并从中调用成员函数。这就是静态函数的样子:

void GraphicsSubsystem::renderScene(Subsystem * subsystem, Event * event) {
   GraphicsSubsystem * graphics = static_cast<GraphicsSubsystem *>(subsystem);
   graphics->renderScene();
}
void ScriptingSubsystem::runLine(Subsystem * subsystem, Event * event) {
   ScriptingSubsystem * scripting = static_cast<ScriptingSubsystem *>(subsystem);
   Event1<String> * e = static_cast<Event1<String> *>(event);
   scripting->runLine(e->getArg());
}

参数总是抽象子系统类和基事件类。runLine函数我没有问题,因为我没有在每一帧上运行一行代码。然而,renderScene函数让我有点不舒服。

So博士,这是我的问题。在每一帧上静态强制转换对象是否比在每一帧上调用虚函数更快?

是的,静态强制转换是一个相当快的操作。静态强制转换是静态的,即在编译时所有形参都是已知的,在运行时指针被常量修改。

但是,您也不应该对虚函数调用过于悲观。虽然它们比普通的函数调用慢,但在许多时间尺度上它们仍然非常非常快,特别是与渲染场景的成本相比。我很难想象一款游戏会因为每帧O(1)虚拟函数调用而变得缓慢。首先要做一个干净的设计,当你观察到一款缓慢的游戏时,要担心它的速度慢,并可以分析它到底在哪里慢。

一般的答案是,这取决于具体情况。

然而,试着想象一下运行时在调用虚函数时做了什么——它获取this指针,在虚方法表中查找函数的指针,然后运行函数。

对于我来说,不清楚为什么这应该比静态强制转换慢。

如果我是你,我会使用这两种方法创建一个原型代码/存根,并调用它一百万次并测量性能。

这个问题讨论的是静态强制转换的成本,这个问题讨论的是虚拟调度的成本。后者解释说,尽管虚函数表查找的代价不是很高,但丢失优化和缓存丢失对性能的影响可能是可观的。

因此你的担忧至少值得考虑。(我最初的想法是,渲染场景所做的工作肯定比调用函数的成本要重要得多。)

@Jiri的评论当然是对的,但真正知道的唯一方法是测量它-我们在这里谈论的效果非常具体到编译器/优化器/CPU聪明。构建测试不会花费很长时间。

如果你需要虚函数的特性,就使用它们。他们在那里是因为他们是有用的。

如果在您的系统上有一种简单而有效的方法来实现它,显然编译器实现者已经这样做了。

相信你的编译器!