This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Increase size of std::function small object buffer
- From: Felix Winterhalter <felix at audiofair dot de>
- To: libstdc++ at gcc dot gnu dot org
- Date: Sat, 30 Jul 2016 14:27:02 +0200
- Subject: Increase size of std::function small object buffer
- Authentication-results: sourceware.org; auth=none
Hello all,
so I've run into the following problem.
I'm using gcc's libstdc++ to do embedded development. In this case its
usually fairly important to make sure that all dynamic allocation is
controlled or best not done at all.
I've been using std::function to implement various callbacks and only
yesterday found out by accident that it actually performs dynamic
allocation for a case where its rather surprising: std::bind of method
pointers with class instances.
I've already started a small discussion on stack overflow:
https://stackoverflow.com/questions/38667268/prevent-stdfunction-in-gcc-from-allocating-memory-or-increase-threshhold/38670041#38670041
and in the gcc irc channel. I'm going to add my example code here as well.
Essentially the gist is the following:
std::function<int()> a = freeFunction; // No dynamic allocation
std::function<int(Class*)> a = &Class::Method; // No dynamic allocation
std::function<int()> a = std::bind(&Class::Method, &classInstance); //
Dynamic allocation!!!
The problem is that this is actually rather unexpected behavior in my
opinion as I would assume that having a bound method pointer function is
something you'd definitely want to support without dynamic allocation.
It gets even worse when you take into account one answer on stack
overflow which says that:
std::function<int()> f = [=]{ return classInstance.Method(); };
Actually does not perform dynamic allocation. I would however expect
this to be more of a clever workaround than the way the standard would
want you to use this since this is not an instance of very transparent code.
I see a simple solution to this:
Increase the internal buffer of std::function to 24 bytes from 16 bytes
as the method pointer uses 16 bytes while the pointer to class instance
uses another 8 bytes.
On a side note:
Clangs libstdc++ does not perform dynamic allocation here
also
Using a custom allocator is not a solution as it will not carry over to
value copies of the std::function object (this appears to be a defect in
the standard which they however do not acknowledge as such) see:
https://stackoverflow.com/questions/32596021/whats-the-point-of-stdfunction-constructor-with-custom-allocator-but-no-other
and
https://cplusplus.github.io/LWG/lwg-closed.html#2386
// Example program
#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;
}