Zik332
Zik332

Reputation: 155

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

Bare in mind that I am trying to make the code as fast as I can, so suggestions that contain allocations or other slow code is not really an option.

I have a rendering system for a game I am building, and I am trying to store all the rendering process in a vector of functions, for example:

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

At the end of each loop, I go through all the rendering that I stored and I render them, after that I clear the array.

I want to be able to have a vector that contains multiple different functions AND to be able to access variables that are local or copied into the function (for example, lambda capture let me send variables to the functions without changing the signature of the function) or be able to store member-functions so I can access properties of the object.

Now, I tried several things to make this system work:

Thing I want from the system:

Anyone have idea how to implement such a system?

If my explanation was not good enough here is an example:

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

Upvotes: 3

Views: 810

Answers (1)

so suggestions that contain allocations or other slow code is not really an option.

This shows a misconception. Allocation is not necessarily slow. And code avoiding heap allocation is not always fast. And you could provide your own allocators (most standard containers have an optional allocator template argument, e.g. the second template argument to std::vector) if you believe you could make a faster one.

However, you could store smart pointers to lambdas, perhaps using std::unique_ptr<std::function<void(void)>>

You do need to manage the lifetime of these lambdas.

Problem: std::function seem to allocate and deallocate memory every iteration of the loop, which is really critical to me,

Are you really sure of that? Did you really benchmark? In many cases, it would be fast enough for you (and the performance issues might be elsewhere).

I don't think that for game rendering, the bottleneck will be where you think today it is. You need to profile your entire game. Of course, for benchmarking purposes, you need to enable compiler optimizations. See also this (and follow the links there).

A typical heap allocation (with ::operator new or malloc ....) usually takes less than a microsecond (but sometimes much more). In most cases (but not all) that is not a performance issue.

(I want a single std::vector that contain all the functions)

This is quite easy. Make a tagged union type, perhaps using std::variant, then have a std::vector of such types. Or, if you have a vector of pointers, make a common superclass (with some virtual functions) and have a vector of pointers to that class.

Upvotes: 4

Related Questions