虚拟方法VS std :: function成员变量的性能

Dhi*_*sen 8 c++ performance lambda inheritance virtual-functions

游戏引擎有这个类:

class  MouseListener{
public :
MouseListener();
virtual void OnMouseDown(int mx,int my);
virtual void OnMouseUp(int mx,int my);
.
.
.
};
Run Code Online (Sandbox Code Playgroud)

每个想要监听鼠标输入的对象都必须固有该类并覆盖它的方法.为了不必每次都声明一个新类型,该类被修改为:

class  MouseListener{
public :
MouseListener();
std::function <void(MouseListener*,int,int)>OnMouseDown;
std::function <void(MouseListener*,int,int)>OnMouseUp;
.
.
.
};
Run Code Online (Sandbox Code Playgroud)

现在使用这个类可以这样做:

MouseListener * m = new MouseListener();
m->OnMouseDown = [](MouseListener * thiz,int x,int y){
   //// do something
};
Run Code Online (Sandbox Code Playgroud)

在输入系统中,只调用非空(已分配)的MouseListener函数(使用thiz =鼠标侦听器).知道该类是从外部库(静态链接)使用的,这在性能方面更好吗?

注意:除非收到鼠标事件,否则不会调用这些函数,当发生这种情况时,会为每个听取鼠标输入的对象调用相应的函数(不应该是批次,<50)

Dav*_*aim 8

它实际上取决于虚函数与函数对象的用法.

虽然std::function 可能比虚拟调用*慢,但是std::function缓冲区优化很短,这可能会阻止动态内存分配(您可能在虚拟版本中进行分配).
这本身可能胜过你可能对常规多态性做的任何事情.

在内部(但不保证),std::function对象无论如何都使用虚拟调用进行类型擦除,所以我认为差异可以忽略不计.

提示 - 确保检查是否std::function有效(通过呼叫if(static_cast<bool>(myFunction))).编译器将插入一个检查以查看该函数是否为空.如果没有,该程序将抛出std::bad_function_call.开发人员检查将使编译器删除他的检查以及与std::bad_function_call何时启用优化相关的代码,从而留下更"平滑"的汇编代码.

在我的经验中处理性能和C++时,优化内存分配,线程间争用和错误的数据结构更加重要,这些结构对缓存起作用.通常,它比优化CPU的东西更有价值的优化(比如虚拟功能vs. std::function)

*一个不错的编译器可以将类型擦除实现为虚函数+给定的lambda作为内联函数.从理论上讲,它不应该比常规虚函数慢.另一方面,如果函数对象获得非可嵌入的可调用,如函数指针,它可以使用两个间接来启动该函数.这可能比常规虚拟呼叫慢.这取决于.

  • 我现在与OP具有相同的困境,但是由于覆盖OnMouseDown通常是可选的,因此,如果您有1000个对象,而其中只有200个覆盖它,则将对虚拟OnMouseDown进行1000次调用。但是,如果您使用std :: function代替(或使用普通的c函数指针),则可以检查其是否为空,并且不占用调用开销,这应该会使事情变得更快。再说一次,分支条件是半调用(跳转),但是由于它们是短跳转,所以如果我正确的话,它们需要5个周期。虚拟呼叫将有90%的时间是FAR呼叫。 (3认同)
  • 注意:您不需要 `if (static_cast&lt;bool&gt;(myFunction))`,因为在 C++11 中,有一种称为 `显式运算符 bool() const` 的上下文转换。这意味着在某些情况下(if、while、&amp;&amp;、...),运算符变得隐式,您可以只执行“if (myFunction)”。 (2认同)