将lambdas/functions存储在std::vector中,而不使用std::function

Store lambdas/functions in std::vector without std::function

本文关键字:std function vector functions 存储 lambdas      更新时间:2023-10-16

请记住,我正在尝试尽可能快地编写代码,因此包含分配或其他慢速代码的建议实际上不是一种选择。

我有一个用于我正在构建的游戏的渲染系统,我正在尝试将所有渲染过程存储在函数向量中,例如:

if(Monster.IsAlive)
{
PushRender([...](){ // "..." means some stuff that I need to capture
// Rendering the monster here...
});
}

在每个循环结束时,我遍历我存储的所有渲染并渲染它们,然后清除数组。

我希望能够拥有一个包含多个不同函数的向量,并且能够访问局部变量或复制到函数中的变量(例如,lambda 捕获允许我将变量发送到函数而不更改函数的签名)或能够存储成员函数以便我可以访问对象的属性。

现在,我尝试了几件事来使这个系统工作:

  • 我试图将所有内容存储在std::vector<std::function<void()>>

    问题std::function似乎在循环的每次迭代中分配和释放内存,这对我来说真的很关键,所以除非我能找到为什么在不影响性能的情况下使用它,否则std::function不是一个选择。

  • 尝试使用std::vector<void(*Render)()>

    问题:我不能在此选项中使用 lambda,也不能在这些选项中使用成员函数(至少我不能)。所以只有非成员的函数对我来说是一个问题。

我想从系统中得到的东西:

  • 要快,尽可能快。
  • 能够在不使用模板的情况下运行多个不同的功能(我想要一个包含所有功能的std::vector)

有人知道如何实现这样的系统吗?

如果我的解释不够好,这里有一个例子:

using Func = ...; // std::function<void()> for example
std::vector<Func> Functions;
while(Running)
{
// clear all the rendering
Functions.clear();
if(Monster.IsAlive)
{
// 1. 
Functions.push_back(Monster.Render); // Monster.Render = Function
// Or 2.
Functions.push_back(RenderMonster); // RenderMonster = Function
// Or 3.
Functions.push_back([] () {
RenderImage(MonsterImage, X, Y);
//....
}); 
}
//... More code here
// Render everything that is saved so far 
for(Func func : Functions)
{
func();
}
}

所以包含分配或其他慢速代码的建议实际上不是一个选项。

这显示出一种误解。分配不一定很慢。避免堆分配的代码并不总是很快。如果你认为你可以做一个更快的分配器,你可以提供你自己的分配器(大多数标准容器都有一个可选的分配器模板参数,例如std::vector的第二个模板参数)。

但是,您可以存储指向 lambda 的智能指针,也许可以使用std::unique_ptr<std::function<void(void)>>

您确实需要管理这些 lambda 的生存期。

问题:std::function似乎每次循环迭代都会分配和释放内存,这对我来说真的很关键,

你真的确定吗?你真的对标吗?在许多情况下,它对您来说足够快(性能问题可能在其他地方)。

我不认为对于游戏渲染来说,瓶颈会是你今天认为的地方。您需要分析整个游戏。当然,出于基准测试目的,您需要启用编译器优化。另请参阅此内容(并点击那里的链接)。

典型的堆分配(具有::operator newmalloc...)通常需要不到一微秒(但有时更多)。在大多数情况下(但不是全部),这不是性能问题。

(我想要一个包含所有函数的 std::vector)

这很容易。创建一个标记的联合类型,也许使用std::variant,然后std::vector此类类型。或者,如果你有一个指针向量,创建一个公共超类(带有一些虚函数),并有一个指向该类的指针向量。