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

时间:2018-01-02 16:24:47

标签: c++ vector lambda

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

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

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();
    }
}

1 个答案:

答案 0 :(得分:4)

  

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

这表明存在误解。分配不一定很慢。避免堆分配的代码并不总是很快。并且您可以提供自己的allocators(大多数标准containers具有可选的分配器模板参数,例如std::vector的第二个模板参数),如果您认为可以制作更快的参数。

但是,您可以使用std::unique_ptr<std::function<void(void)>>

存储指向lambdas的智能指针

你需要管理这些lambda的生命周期。

  

问题:std::function似乎在循环的每次迭代中分配和释放内存,这对我来说非常关键,

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

我不认为对于游戏渲染而言,瓶颈将是你今天的想法。 您需要profile 整个游戏。当然,出于基准测试目的,您需要启用compiler optimizations。另请参阅this(并按照其中的链接)。

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

  

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

这很容易。制作tagged union类型,可能使用std::variant,然后使用此类型std::vector。或者,如果你有一个指针向量,创建一个共同的超类(带有一些虚函数),并有一个指向该类的指针向量。