0

The size of a lambda expression object with an empty capture-list is 1

But if you store it into std:function, its size becomes 48 (on my platform)

Imagine when you have a container that stores thousands of functions

The memory usage will be 48-times bigger if you store them into std::function

Even a lambda object capturing a small object (like an 8-sized pointer) is much smaller than a std::function

Do you have any better idea to save that unnecessary space-usage?

aleck099
  • 428
  • 2
  • 10
  • Does this answer your question? [Why does a lambda have a size of 1 byte?](https://stackoverflow.com/questions/37481767/why-does-a-lambda-have-a-size-of-1-byte) – Jean-Baptiste Yunès Apr 11 '22 at 09:33
  • @Jean-BaptisteYunès No, I know the lambda things, the problem is about `std::function` – aleck099 Apr 11 '22 at 09:58
  • 3
    If your lambdas are all non-capturing then just use function pointers otherwise, unless they are all the same lambda, you need to pay the cost of `std::function` to provide the type erasure. If you need to worry about 48K of memory then your container with thousands of functions is probably not appropriate anyway – Alan Birtles Apr 11 '22 at 10:09

1 Answers1

2

This is the price you pay for not needing to know the type of the function. All std::function<void()>s are interchangeable no matter which lambda they came from. If you want to store lots of the same type of function (with different captures) in a vector, you can make it a functor instead of a lambda (so that it has a name) and make a vector of that type.

Example: With lambda:

std::vector<std::function<void()>> funcs;
for(int i = 0; i < 10000; i++)
    funcs.push_back([i]() {std::cout << i << std::endl;});
for(auto& func : funcs)
    func();

With functor:

struct number_printing_function {
    int i;
    number_printing_function(int i) : i(i) {}
    void operator()() {
        std::cout << i << std::endl;
    }
};

std::vector<number_printing_function> funcs;
for(int i = 0; i < 10000; i++)
    funcs.push_back(number_printing_function(i));
    // or funcs.emplace_back(i);

for(auto& func : funcs)
    func();

IMO this is a bit useless, because we might as well store a vector of ints and stop pretending they are functions. When you have many functors of the same type you already know what they do, so just do it. Really, the code above is just the code below, but with extra steps:

std::vector<int> ints;
for(int i = 0; i < 10000; i++)
    ints.push_back(i);
for(auto& i : ints)
    std::cout << i << std::endl;
user253751
  • 57,427
  • 7
  • 48
  • 90
  • 1
    you can return a lambda from a function, e.g. `auto make_func(int i) { return [i](){ std::cout << i << std::endl; }; }`, `std::vector funcs; std::generate_n(std::back_inserter(funcs), 10000, make_func);` – Caleth Apr 11 '22 at 13:22
  • @Caleth While this is true, it's much more convenient to give the functor a name so you can do things like pass it around. I mean, great, you created a vector of lambdas, but how are you going to store it in a member variable or pass it as a parameter? A name is a lot easier to type and remember than a decltype expression. – Raymond Chen Apr 12 '22 at 13:34