请记住,我正在尝试尽可能快地编写代码,因此包含分配或其他慢速代码的建议实际上不是一种选择。
我正在构建一个游戏的渲染系统,我试图将所有渲染过程存储在一个函数向量中,例如:
if(Monster.IsAlive)
{
PushRender([...](){ // "..." means some stuff that I need to capture
// Rendering the monster here...
});
}
在每个循环结束时,我会浏览我存储的所有渲染,然后渲染它们,然后清除数组。
我希望能够拥有一个包含多个不同函数的向量,并且能够访问本地或复制到函数中的变量(例如,lambda capture让我将变量发送到函数而不更改签名函数)或能够存储成员函数,以便我可以访问对象的属性。
现在,我尝试了几个方法来使这个系统工作:
我尝试将所有内容存储在std::vector<std::function<void()>>
:
问题:std::function
似乎在循环的每次迭代中分配和释放内存,这对我来说非常关键,所以std::function
不是一个选项,除非我能找到为什么要在没有性能影响的情况下使用它。
尝试使用std::vector<void(*Render)()>
:
问题:我不能在这个选项中使用lambdas,而且我也不能使用成员函数(至少我不能)。因此,只有非成员的功能对我来说才是问题。
我想从系统中获取:
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();
}
}
答案 0 :(得分:4)
所以包含分配或其他慢速代码的建议实际上并不是一种选择。
这表明存在误解。分配不一定很慢。避免堆分配的代码并不总是很快。并且您可以提供自己的allocators(大多数标准containers具有可选的分配器模板参数,例如std::vector
的第二个模板参数),如果您认为可以制作更快的参数。
但是,您可以使用std::unique_ptr<std::function<void(void)>>
你需要管理这些lambda的生命周期。
你真的很确定吗? 您真的是基准吗?在很多情况下,它对您来说足够快(而且性能问题可能在其他地方)。问题:
std::function
似乎在循环的每次迭代中分配和释放内存,这对我来说非常关键,
我不认为对于游戏渲染而言,瓶颈将是你今天的想法。 您需要profile 整个游戏。当然,出于基准测试目的,您需要启用compiler optimizations。另请参阅this(并按照其中的链接)。
典型的堆分配(::operator new
或malloc
....)通常需要不到一微秒(但有时甚至更多)。在大多数情况下(但不是全部)这不是性能问题。
(我想要一个包含所有函数的std :: vector)
这很容易。制作tagged union类型,可能使用std::variant
,然后使用此类型std::vector
。或者,如果你有一个指针向量,创建一个共同的超类(带有一些虚函数),并有一个指向该类的指针向量。