This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Increase size of std::function small object buffer


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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]