This code is just for illustrating the question.
#include <functional> struct MyCallBack { void Fire() { } }; int main() { MyCallBack cb; std::function<void(void)> func = std::bind(&MyCallBack::Fire, &cb); }
Experiments with valgrind shows that the line assigning to func
dynamically allocates about 24 bytes with gcc 7.1.1 on linux.
In the real code, I have a few handfuls of different structs all with a void(void)
member function that gets stored in ~10 million std::function<void(void)>
.
Is there any way I can avoid memory being dynamically allocated when doing std::function<void(void)> func = std::bind(&MyCallBack::Fire, &cb);
? (Or otherwise assigning these member function to a std::function
)
std::function can store objects of arbitrary size, this means it must perform dynamic memory allocation in some cases. there are certain types for which std::function is guaranteed not to throw exceptions. This implies that there are certain types it must store without dynamic memory allocation.
Many std::function implementations will avoid allocations and use space inside the function class itself rather than allocating if the callback it wraps is "small enough" and has trivial copying. However, the standard does not require this, only suggests it.
If it is small, like 3-5 CPU instructions then yes std::function will make it slower, because std::function is not inlined into outer calling code. You should use only lambda and pass lambda as template parameter to other functions, lambdas are inlined into calling code.
According to cppreference ::std::variant must not allocate dynamic memory.
Unfortunately, allocators for std::function
has been dropped in C++17.
Now the accepted solution to avoid dynamic allocations inside std::function
is to use lambdas instead of std::bind
. That does work, at least in GCC - it has enough static space to store the lambda in your case, but not enough space to store the binder object.
std::function<void()> func = [&cb]{ cb.Fire(); }; // sizeof lambda is sizeof(MyCallBack*), which is small enough
As a general rule, with most implementations, and with a lambda which captures only a single pointer (or a reference), you will avoid dynamic allocations inside std::function
with this technique (it is also generally better approach as other answer suggests).
Keep in mind, for that to work you need guarantee that this lambda will outlive the std::function
. Obviously, it is not always possible, and sometime you have to capture state by (large) copy. If that happens, there is no way currently to eliminate dynamic allocations in functions, other than tinker with STL yourself (obviously, not recommended in general case, but could be done in some specific cases).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With