C++ 手动使用多种类型比多态更快?
我需要制作一个要渲染的对象列表。。。现在我开始思考,不管风格或个人偏好,只考虑性能,还有什么选择更快 多类型/开关语句:C++ 手动使用多种类型比多态更快?,c++,C++,我需要制作一个要渲染的对象列表。。。现在我开始思考,不管风格或个人偏好,只考虑性能,还有什么选择更快 多类型/开关语句: void Object::Render() { switch(type) { case BUTTON: RenderButton(this); break; case NOT_BUTTON: RenderNotButton(this);
void Object::Render()
{
switch(type)
{
case BUTTON:
RenderButton(this);
break;
case NOT_BUTTON:
RenderNotButton(this);
break;
case WIDGET_ABC:
RenderWidgetAbc(this);
break;
}
}
或多态性:
virtual void Object::Render();
class Button : public Object
{
void Render();
}
编辑1:如果有帮助的话,我要说的是,它将在ARMV6设备中运行
编辑2:当前项目上有零对象(项目目标的一部分是用C++以更为有效的编程方式进行实验),这就是为什么要考虑这个问题。 此外,这将是代码中调用频率最高的部分,如果它是作为switch语句实现的,那么不会调用其他方法,因此它确实是性能关键的
编辑3:这部分代码实际上是处理要转储到GPU的顶点和UV列表,GPU比CPU快,我想以尽可能快的速度抛出顶点和UV。渲染不受CPU限制。此外,它将有多边形对象,而不仅仅是像GUI这样的简单操作系统。我认为性能差异将足够小,因此可以忽略它。然而,可维护性、可测试性和设计将受到很大影响,因此我不会使用第一个版本
我的经验表明,每次我试图用如此小的优化比编译器更聪明时,我最终的结果是主机实际上变小了。您的第一个代码是维护和设计的噩梦。考虑一下当你需要添加新类型时的情况
至于表演。只有分析才能为您各自的平台和环境提供明确的答案。带有开关的版本应该更快,因为多态性要求将对象移动到缓存中,但这实际上是一个微观优化
我会选择多态性,因为代码可以设计得更好。你说的更快是什么意思 使用多态性会更快,因为
- 这样会更好
- 可维护性当然更好(因此对您来说更快,这一点很重要)
- 它允许以简单的方式进行更复杂的设计
使用开关调用适当的方法只是忘记了OOP。这样做毫无意义。仅仅因为缓存命中/未命中,它的速度可能会加快一些CPU周期,但几乎从来都不值得这样做。我运行了以下代码来比较这两者。正如我预期的那样,虚拟函数稍微快一点(我将在下面解释原因) 然后我添加了-02(用于优化)进行构建,结果如下
Virtual Function
Elapsed time 132 milliseconds
button counter = 10000000
notButton counter = 20000000
widgetAbc counter = 30000000
Switch Function
Elapsed time 206 milliseconds
button counter = 20000000
notButton counter = 40000000
widgetAbc counter = 60000000
Virtual Function
Elapsed time 58 milliseconds
button counter = 10000000
notButton counter = 20000000
widgetAbc counter = 30000000
Switch Function
Elapsed time 76 milliseconds
button counter = 20000000
notButton counter = 40000000
widgetAbc counter = 60000000
在这两种情况下,虚拟功能都更快
虽然虚拟函数比非虚拟函数慢,但开销最小。虚拟函数最有可能是函数指针(尽管编译器可以以不同的方式执行)。因此,当调用虚函数时,唯一额外的开销是指针解引用。下面是一个编译器可以为虚拟调用执行的操作的示例。编译器可以做得更优雅一点,但你可以得到这个想法
#include <stdio.h>
class Object
{
public:
// function pointer acting as virtual function call
void (*funcPtr) (void *this_ptr);
};
class Button : public Object
{
public:
Button();
static void virtualFunc(void *this_ptr);
int counter;
};
Button::Button()
:counter(0)
{
// set object function pointer to our "virtual function"
funcPtr = &Button::virtualFunc;
}
void Button::virtualFunc(void *this_ptr)
{
Button *button_ptr = reinterpret_cast<Button*>(this_ptr);
button_ptr->counter++;
}
int main()
{
Object *button = new Button();
// virtual call using a function pointer
button->funcPtr(button);
printf("button counter = %d\n", static_cast<Button*>(button)->counter);
return 0;
}
#包括
类对象
{
公众:
//充当虚拟函数调用的函数指针
作废(*funcPtr)(作废*本文件);
};
类按钮:公共对象
{
公众:
按钮();
静态void virtualFunc(void*this_ptr);
整数计数器;
};
按钮::按钮()
:计数器(0)
{
//将对象函数指针设置为“虚拟函数”
funcPtr=&按钮::virtualFunc;
}
void按钮::virtualFunc(void*此ptr)
{
Button*Button_ptr=重新解释(此_ptr);
按钮->计数器++;
}
int main()
{
对象*按钮=新按钮();
//使用函数指针的虚拟调用
按钮->功能(按钮);
printf(“按钮计数器=%d\n”,静态(按钮)->计数器);
返回0;
}
您为什么要关心哪个更快?您忽略了其他因素,比如可扩展性。速度确实是最不重要的问题,至少在您测量并确认部分代码是热点之前。对于在用户界面中呈现按钮(屏幕上可以容纳多少个按钮?100?),任何可能的性能差异都可以忽略不计。@us2012对于呈现任何内容,与实际渲染的成本相比,虚拟函数调用的成本是无法衡量的。@JamesKanze视情况而定。在处理和渲染成千上万的3D对象(基本体)时,就像在许多(尽管不是全部)视频游戏中一样,每个对象的虚拟函数调用可能是可测量的——更重要的是,它指示了更具象征意义的剪纸。幸运的是,聪明人已经找到了解决这些问题的方法,而不必使用丑陋的开关,部分原因是开关实际上并不更快,存在许多相同的问题。@speeder的“性能”问题在stackoverflow上总是有点问题(特别是对于C/C++标记),如果人们(a)不同意您的用例需要优化,(b)您正在考虑一个他们认为不如“标准做事方式”的优化,或者(c)认为答案很明显,您不应该问,那么他们似乎会对这些人投很低的票。这有点不幸,我同意这个问题不值得-4。这在很大程度上取决于编译器如何实现这一点,但至少在某些机器上,调用虚拟函数比调用开关更快。(对其他人来说,可能不是。)@JamesKanze我同意,但这仍然是一个微观优化。显然,选择一个解决方案而不是o
#include <stdio.h>
class Object
{
public:
// function pointer acting as virtual function call
void (*funcPtr) (void *this_ptr);
};
class Button : public Object
{
public:
Button();
static void virtualFunc(void *this_ptr);
int counter;
};
Button::Button()
:counter(0)
{
// set object function pointer to our "virtual function"
funcPtr = &Button::virtualFunc;
}
void Button::virtualFunc(void *this_ptr)
{
Button *button_ptr = reinterpret_cast<Button*>(this_ptr);
button_ptr->counter++;
}
int main()
{
Object *button = new Button();
// virtual call using a function pointer
button->funcPtr(button);
printf("button counter = %d\n", static_cast<Button*>(button)->counter);
return 0;
}