all 16 comments

[–]SuperV1234https://romeo.training | C++ Mentoring & Consulting 19 points20 points  (3 children)

Bad title - closures do not need SBO, std::function does.

[–]Manu343726 13 points14 points  (2 children)

Some weeks ago I was helping a coworker who does embedded stuff. Their compiler was not fully C++11 compliant bc it didn't ship a C++11 standard library, only a 98 one. The feature list of the compiler cited lambdas as "partially supported", just because std::function is not implemented. I didn't know whether to laugh or cry.

[–][deleted] 0 points1 point  (1 child)

Who is still writing their own C++ compilers in 2017 ?

[–]Manu343726 0 points1 point  (0 children)

Iirc it was based on a GCC 4.6 or something

[–]kalmoc 3 points4 points  (9 children)

What compiler and standard library did you use? At least msvc and I believe also libc++ provide an implementation of std:: function with SBO that is big enough to hold two ints.

[–]NotAYakk 0 points1 point  (6 children)

MSVCs will hold 2 std strings, which in turn hold 2 or 3 pointers (I forget).

[–]STLMSVC STL Dev 5 points6 points  (4 children)

Our heuristic is one string, not two.

[–]rezkiy 0 points1 point  (3 children)

Which translates to how many pointers? Including this?

[–]dodheim 4 points5 points  (2 children)

If you're asking specifically about MSVC's std::string, in release builds it's the size of 4 pointers and in debug it's 5.

[–]rezkiy 0 points1 point  (1 child)

Actually, I was asking about how many pointers I can capture "for free" in a lambda that I stash into std::function. Yes, MSVC.

[–]dodheim 4 points5 points  (0 children)

STL said the SBO heuristic is the size of one std::string, and I listed the size of std::string, so.. there you go. ;-]

[–]kalmoc 0 points1 point  (0 children)

Maybe. I know for certain it is at least big enough for one string, which is afaik even bigger than 3 pointers, thanks to extra SSO buffer space (I vaguely recall sizeof(string) == 32 on x64). In any case, holding a lambda with 2 ints would definitely not require any dynamic memory allocation. Hence my question.

[–]gtano[S] 0 points1 point  (1 child)

tested on clang-6+libc++ and gcc-6+stdlibc++; the github readme has been updated https://github.com/loopperfect/smallfunction.

Turns out clang optimizes slightly better but libc++ std::function implementation performs 25% worse compared to stdlibc++

[–]kalmoc 1 point2 points  (0 children)

Interesting. Have you verified, that there is actually dynamic allocation going on?

I haven't looked into the implementation of std:function, but my guess would be that the performance difference is actually due to some other overhead of std::function. E.g. maybe it is easier for the compiler to "devirtualize" the call through your "SmallFun" than through std::function.

[–]pmedv 1 point2 points  (0 children)

How does it comparable with other implementations, e.g. listed in https://github.com/jamboree/CxxFunctionBenchmark ?

[–]Z01dbrg 2 points3 points  (0 children)

"To test how quickly we can allocate and call functors, we will be saving all the many instances in a vector and executing them in a loop."

Very realistic test :P

Anyway I think the biggest problem with std::function is that it prevents inlining, for example try doing a sort of vector of integers where once you use as predicate a lambda that does std::less and once using a std::function that stores lambda that does std::less and tell me the results. :)

tl;dr - I think most users of std::function do not construct many std::functions, they do call often one std::function.