Comment by spacechild1

Comment by spacechild1 6 months ago

9 replies

> I’ve used std::function<> and I’ve used lambdas and what pushed me away from them were crash reports.

In danger of pointing out the obvious: std::function does note require lambdas. In fact, it has existed long before lambdas where introduced. If you want to avoid lambdas, just use std::bind to bind arguments to regular member functions or free functions. Or pass a lambda that just forwards the captures and arguments to the actual (member) function. There is no reason for regressing to C-style callback functions with user data.

kjksf 6 months ago

I did use bind earlier in SumatraPDF.

There are 2 aspects to this: programmer ergonomics and other (size of code, speed of code, compilation speed, understandability).

Lambdas with variable capture converted to std::function have best ergonomics but at the cost of unnamed, compiler-generated functions that make crash reports hard to read.

My Func0 and Func1<T> approach has similar ergonomics to std::bind. Neither has the problem of potentially crashing in unnamed function but Func0/Func1<T> are better at other (smaller code, faster code, faster compilation).

It's about tradeoffs. I loved the ergonomics of callbacks in C# but I working within limitations of C++ I'm trying to find solutions with attributes important to me.

  • spacechild1 6 months ago

    > but Func0/Func1<T> are better at other (smaller code, faster code, faster compilation).

    I would really question your assumptions about code size, memory usage and runtime performance. See my other comments.

Kranar 6 months ago

> In fact, it has existed long before lambdas where introduced.

Both std::function<> and lambdas were introduced in C++11.

Furthermore absolutely no one should use std::bind, it's an absolute abomination.

  • spacechild1 6 months ago

    You are absolutely right of course! No idea, why I thought std::function existed before C++11. Mea culpa!

    > Furthermore absolutely no one should use std::bind, it's an absolute abomination.

    Agree 100%! I almost always use a wrapper lambda.

    However, it's worth pointing out that C++20 gave us std::bind_front(), which is really useful if you want to just bind the first N arguments:

        struct Foo {
            void bar(int a, int b, int c);
        };
    
        Foo foo;
    
        using Callback = std::function<void(int, int, int)>;
    
        // with std::bind (ugh):
        using namespace std::placeholders;
        Callback cb1(std::bind(&Foo::bar, &foo, _1, _2, _3));
    
        // lambda (without perfect forwarding):
        Callback cb2([&foo](auto&&... args) { foo.bar(args...); });
    
        // lambda (with perfect forwarding):
        Callback cb3([&foo](auto&&... args) { foo.bar(std::forward<decltype(args)>(args)...); });
    
        // std::bind_front
        Callback cb4(std::bind_front(&Foo::bar, &foo));
    
    I think std::bind_front() is the clear winner here.
mandarax8 6 months ago

std::bind is bad for him for the same reasons std::function is bad though

  • spacechild1 6 months ago

    Why? If the bound (member) function crashes, you should get a perfectly useable crash report. AFAIU his problem was that lambdas are anonymous function objects. This is not the case here, because the actual code resides in a regular (member) function.

    • dustbunny 6 months ago

      Does a stack trace from a crash in a bound function show the line number of where the bind() took place?

      • delusional 6 months ago

        Assuming the stack trace is generated by walking up the stack at the time when the crash happened, nothing that works like a C function pointer would ever do that. Assigning a a pointer to a memory location doesn't generate a stack frame, so there's no residual left in the stack that could be walked back.

        A simple example. If you were to bind a function pointer in one stack frame, and the immediately return it to the parent stack frame which then invokes that bound pointer, the stack that bound the now called function would literally not exist anymore.