Search code examples
c++templatesc++11bindstdbind

Reducing std::bind template code bloat?


I've written an object that stores a std::function<void(void*)>, which is passed in as an argument to the constructor. The object will later call back this std::function at some point in the future. This is implemented and working great.

In each class which uses this object, they call the constructor in the initialization list like so:

mCallbackObj(std::bind(&MyClass::MyFunc, this, _1))

However, I've found that every class which contains this object as a member is increasing my codespace by ~2K. With potentially hundreds of places where this object will be used, and limited codespace options (this is an embedded product), a 2k hit per use isn't acceptable.

One interesting observation is that if a class has a second object:

mCallbackObj2(std::bind(&MyClass::MyOtherFunc, this, _1))

this only increases codespace by some ~150 bytes - very acceptable! It is only when the object is used in different classes that I see the 2K hit. Putting the classes all in one .cpp file doesn't help - still a 2k hit per class that contains this object.

I've played around with using extern template class std::function<void(void*)>;, but this had no impact on ROM size.

I am using gcc 4.8. I'd love to use std::function and std::bind, but am about to give up and switch to class method pointers. They wouldn't be nearly as clean, but hopefully more ROM efficient.

Before I give up on this, are there any other options to help reduce my template codespace bloat?


Solution

  • I dug into this a bit more and watched @John's video on std::function. In the video, STL recommends using lambdas over std::bind for a few reasons.

    I tried converting the code to use a Lambda, which is exactly what @Igor Tandetnik recommended above. It is significantly better.

    mCallbackObj(std::bind(&MyClass::MyFunc, this, _1))
    

    Takes an additional 2,888 bytes of codespace. Instead using

    mCallbackObj([this](void *info){MyFunc(info);})
    

    Only takes an additional 812 bytes! This is significantly better, and good enough for my use-case. For C++ programmers unfamiliar with the syntax of std::bind, the lambda solution is also easier to read.


    Update -

    After bumping to GCC 6.0 and tweaking our compiler flags (we weren't always passing in -O2 previously), I've retested this.

    Lambda:            216 bytes
    std::bind:         221 bytes
    function pointer:  228 bytes
    

    All 3 are now much more reasonable. We are mostly using lambdas, as they are the easiest to read once developers are familiar with the syntax.