Search code examples
c++c++11gccmemory-managementstd-function

Prevent std::function in gcc from allocating memory or increase threshhold


Is there any way to prevent std::function in gcc from dynamically allocating memory for larger function objects?

I would have expected the following code to work without dynamic allocation:

#include <functional>
#include <iostream>

// replace operator new and delete to log allocations
void* operator new (std::size_t n) {
    std::cout << "Allocating " << n << " bytes" << std::endl;
    return malloc(n);
}
void operator delete(void* p) throw() {
    free(p);
}

  class TestPlate
  {
    private:
        int value;

    public:
        int getValue(){ return value; }
        void setValue(int newValue) { value = newValue; }

        int doStuff(const std::function<int()>& stuff) { return stuff(); }

  };

int main()
{
    TestPlate testor;
    testor.setValue(15);
    const std::function<int()>& func =  std::bind(&TestPlate::getValue, &testor);

    std::cout << testor.doStuff(func) << std::endl;
    testor.setValue(25);
    std::cout << testor.doStuff(func) << std::endl;
}

However it allocates 24 bytes. As far as I am able to tell this is because the pointer to method requires 16 bytes and the pointer to the class instance another 8 bytes. This seems to be either A larger than the internal memory available to the function object or B a plain bug.

I was wondering whether there are is any way to circumvent this type of behavior without changing the signature of the std::function or creating a lot of additional wrapper code.


Solution

  • Unfortunately GCC's function only has space for a pointer to member function stored internally, so the result of your bind expression doesn't fit.

    You can use a lambda expression instead though:

    std::function<int()> f = [&]{ return testor.getValue(); };
    

    This only requires space for a closure type containing a reference to testor (which is half the size of a pointer to member, and a third of the size of the bind result), and GCC defines that closure so it can be stored in a std::function.