Search code examples
c++c++11std-function

small object optimization useless in using std::function


Many topics told us that use small object like lambda expression could avoid heap allocation when using std::function. But my study shows not that way.

This is my experiment code, very simple

#include <iostream>
#include <functional>

using namespace std;

typedef std::function<int(int, int)> FUNC_PROTO;

class Test
{
public:
    int Add(int x, int y) { return x + y; }
};

int main()
{
    Test test;
    FUNC_PROTO functor = [&test](int a, int b) {return test.Add(a, b); };
    cout << functor(1, 2) << endl;
}

And I compile it on centos7, with gcc version 4.8.5 20150623 But the valgrind shows this:

==22903== HEAP SUMMARY:
==22903==     in use at exit: 0 bytes in 0 blocks
==22903==   total heap usage: 1 allocs, 1 frees, 8 bytes allocated

Even if I remove the reference capture, just a plain lambda function. It still cost 1 byte heap allocation.

Is there somthing wrong of me to get small object optimization.

Update:

Thanks for the repies. I think I should add more detail of my experiment.

In order to eliminate the possible cause of refrence capturing. I removed capture, code like this:

FUNC_PROTO functor = [](int a, int b) {return a + b; };

Valgrind shows this:

==16691==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated

Still 1 byte heap allocation.

I also tried this to eliminate possible influence of lambda itself(which I think not)

FUNC_PROTO functor = [](int a, int b) {return a + b; };
FUNC_PROTO functor2 = [](int a, int b) {return a * b; };

FUNC_PROTO test = nullptr;
for ( int i = 0; i < 10; ++i)
{
    if (i % 2 == 0)
    {
        test = functor;
    }
    else
    {
        test = functor2;
    }
}

Valgrind shows:

==17414==   total heap usage: 12 allocs, 12 frees, 12 bytes allocated

That could prove that the functors are not fully stack based object.

And this is my build script:

g++ test.cpp -o test  -std=c++11 -g -O3 -DNDEBUG

This is my valgrind script:

valgrind --log-file=valgrind.log --tool=memcheck --leak-check=full --show-leak-kinds=all ./test

Solution

  • Older versions of libstdc++, like the one shipped by gcc 4.8.5, seem to only optimise function pointers to not allocate (as seen here).

    Since the std::function implementation does not have the small object optimisation that you want, you will have to use an alternative implementation. Either upgrade your compiler or use boost::function, which is essentially the same as std::function.