Bind VS Lambda

Bind Vs Lambda?

As you said, bind and lambdas don't quite exactly aim at the same goal.

For instance, for using and composing STL algorithms, lambdas are clear winners, IMHO.

To illustrate, I remember a really funny answer, here on stack overflow, where someone asked for ideas of hex magic numbers, (like 0xDEADBEEF, 0xCAFEBABE, 0xDEADDEAD etc.) and was told that if he were a real C++ programmer he would simply have download a list of English words and use a simple one-liner of C++ :)

#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

int main()
{
using namespace boost::lambda;
std::ifstream ifs("wordsEn.txt");
std::remove_copy_if(
std::istream_iterator<std::string>(ifs),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"),
bind(&std::string::size, _1) != 8u
||
bind(
static_cast<std::string::size_type (std::string::*)(const char*, std::string::size_type) const>(
&std::string::find_first_not_of
),
_1,
"abcdef",
0u
) != std::string::npos
);
}

This snippet, in pure C++98, open the English words file, scan each word and print only those of length 8 with 'a', 'b', 'c', 'd', 'e' or 'f' letters.

Now, turn on C++0X and lambda :

#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>

int main()
{
std::ifstream ifs("wordsEn.txt");
std::copy_if(
std::istream_iterator<std::string>(ifs),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[](const std::string& s)
{
return (s.size() == 8 &&
s.find_first_not_of("abcdef") == std::string::npos);
}
);
}

This is still a bit heavy to read (mainly because of the istream_iterator business), but a lot simpler than the bind version :)

Why use std::bind over lambdas in C++14?

Scott Meyers gave a talk about this. This is what I remember:

In C++14 there is nothing useful bind can do that can't also be done with lambdas.

In C++11 however there are some things that can't be done with lambdas:

  1. You can't move the variables while capturing when creating the lambdas. Variables are always captured as lvalues. For bind you can write:

    auto f1 = std::bind(f, 42, _1, std::move(v));
  2. Expressions can't be captured, only identifiers can. For bind you can write:

    auto f1 = std::bind(f, 42, _1, a + b);
  3. Overloading arguments for function objects. This was already mentioned in the question.

  4. Impossible to perfect-forward arguments

In C++14 all of these possible.

  1. Move example:

    auto f1 = [v = std::move(v)](auto arg) { f(42, arg, std::move(v)); };
  2. Expression example:

    auto f1 = [sum = a + b](auto arg) { f(42, arg, sum); };
  3. See question

  4. Perfect forwarding: You can write

    auto f1 = [=](auto&& arg) { f(42, std::forward<decltype(arg)>(arg)); };

Some disadvantages of bind:

  • Bind binds by name and as a result if you have multiple functions with the same name (overloaded functions) bind doesn't know which one to use. The following example won't compile, while lambdas wouldn't have a problem with it:

    void f(int); void f(char); auto f1 = std::bind(f, _1, 42);
  • When using bind functions are less likely to be inlined

On the other hand lambdas might theoretically generate more template code than bind. Since for each lambda you get a unique type. For bind it is only when you have different argument types and a different function (I guess that in practice however it doesn't happen very often that you bind several time with the same arguments and function).

What Jonathan Wakely mentioned in his answer is actually one more reason not to use bind. I can't see why you would want to silently ignore arguments.

Efficiency of std::bind vs lambda

Is there any difference in the performance of these approaches?

Perhaps, perhaps not; as commenters suggest - profile to check, or look at the assemby code you get (e.g. using the GodBolt Compiler Explorer). But you're asking the wrong question, for two main reasons:

  1. You should probably not be passing lambda's, nor bind() results, around in the part of your code that's performance-critical.
  2. You should definitely avoid invoking arbitrary functions via function pointer or std::function variables in performance-critical areas of your code (except if this can be de-virtualized and inlined by the compiler).

and one mind reason:


  1. Lambdas (and std::bind()'s) are usable, and useful, without being wrapped in std::function; this wrapper has its own performance penalty, so you would only be comparing one way of using these constructs.

Bottom line recommendation: Just use Lambdas. They're cleaner, easier to understand, cheaper to compile, and more flexible syntactically. So don't worry and be happy :-) . And in performance-critical code, either use Lambda's without std::function, or don't use any of the two.

std::bind vs lambda performance

I assume that lambda cannot be that better than bind.

That's quite a preconception.

Lambdas are tied into the compiler internals, so extra optimization opportunities may be found. Moreover, they're designed to avoid inefficiency.

However, there are probably no compiler optimization tricks happening here. The likely culprit is the argument to bind, bind(&decltype(result)::eval, &result). You are passing a pointer-to-member-function (PTMF) and an object. Unlike the lambda type, the PTMF does not capture what function actually gets called; it only contains the function signature (parameter and return types). The slow loop is using an indirect branch function call, because the compiler failed to resolve the function pointer through constant propagation.

If you rename the member eval() to operator () () and get rid of bind, then the explicit object will essentially behave like the lambda and the performance difference should disappear.

Why use `std::bind_front` over lambdas in C++20?

bind_front binds the first X parameters, but if the callable calls for more parameters, they get tacked onto the end. This makes bind_front very readable when you're only binding the first few parameters of a function.

The obvious example would be creating a callable for a member function that is bound to a specific instance:

type *instance = ...;

//lambda
auto func = [instance](auto &&... args) -> decltype(auto) {return instance->function(std::forward<decltype(args)>(args)...);}

//bind
auto func = std::bind_front(&type::function, instance);

The bind_front version is a lot less noisy. It gets right to the point, having exactly 3 named things: bind_front, the member function to be called, and the instance on which it will be called. And that's all that our situation calls for: a marker to denote that we're creating a binding of the first parameters of a function, the function to be bound, and the parameter we want to bind. There is no extraneous syntax or other details.

By contrast, the lambda has a lot of stuff we just don't care about at this location. The auto... args bit, the std::forward stuff, etc. It's a bit harder to figure out what it's doing, and it's definitely much longer to read.

Note that bind_front doesn't allow bind's placeholders at all, so it's not really a replacement. It's more a shorthand for the most useful forms of bind.

Is std::bind still useful compared to lambdas?

You can capture by value or by reference, and the problem is that capture by value really means 'capture by copy'. This is a show stopper for a move-only type. So you can't use a lambda to do the following:

struct foo { void bar() {} };

std::unique_ptr<foo> f { new foo };
auto bound = std::bind(&foo::bar, std::move(f));
static_assert( std::is_move_constructible<decltype(bound)>::value, "" );
bound();

IIRC the Standard Committee briefly considered allowing arbitrary expression inside a lambda capture list to solve this (which could look like [std::move(f)] { return f.bar(); }), but I don't think there was a solid proposal and C++11 was already running late.

That and the restriction to monomorphic behaviour with lambdas are the deal breakers for me.

Lambda functions vs bind, memory! (and performance)

Closures (or arrow functions, aka lambdas) don't cause memory leaks

Can someone to confirm or infirm if the local variables (here el) can't be cleared by the garbage collector? Or, are modern browsers capable to detect they are unused in the closure?

Yes, modern JavaScript engines are able to detect variables from parent scopes that are visible from a closure but unused. I found a way to prove that.

Step 1: the closure uses a variable of 10 MB

I used this code in Chromium:

class Abc {
constructor() {
let arr = new Uint8Array(1024*1024*10) // 10 MB
let el = document.getElementById("my-btn")
if (el)
el.addEventListener("click", ev => this.onClick(ev, arr))
}
onClick(ev) {
console.log("Clicked!", ev.target)
}
}

new Abc()

Notice the variable arr of type Uint8Array. It is a typed array with a size of 10 megabytes. In this first version, the variable arr is used in the closure.

Then, in the developer tools of Chromium, tab "Profiles", I take a Heap Snapshot:

Snapshot 1: the variable <code>arr</code> is used in the closure

After ordering by decreasing size, the first row is: "system / JSArrayBufferData" with a size of 10 MB. It is our variable arr.

Step 2: the variable of 10 MB is visible but unused in the closure

Now I just remove the arr parameter in this line of code:

            el.addEventListener("click", ev => this.onClick(ev))

Then, a second snapshot:

Snapshot 2: the variable <code>arr</code> is not used in the closure

The first row has vanished.

This experience confirms that the garbage collector is capable to clean variables from parent scopes that are visible but unused in active closures.

About Function.prototype.bind

I quote the Google JavaScript Style Guide, section on arrow functions:

Never call f.bind(this) or goog.bind(f, this) (and avoid writing const self = this). All of these can be expressed more clearly and less error-prone with an arrow function. This is particularly useful for callbacks, which sometimes pass unexpected additional arguments.

Google clearly recommends to use lambdas rather than Function.prototype.bind.

Related:

  • Why is bind slower than a closure?
  • A benchmark
  • Arrow functions vs. bind() from Dr. Axel Rauschmayer

How to replace std::bind with lambda within steady_timer::async_wait

Your lambda doesn't have the required signature.

Based the boost documentation, the callback takes a const boost::system::error_code& argument. std::bind lets you be a bit looser in the function signature (Why std::bind can be assigned to argument-mismatched std::function?), but lambdas need to be an exact match.

The following code seems to work for me

    timer_.async_wait([this](auto const &ec) {
print();
});

Does bind() have any advantage (other than compatibility) over C++11 lambdas?

Yes: It can (sometimes) significantly affect the output sizes.

If your lambdas are different from each other in any way, they will generate different code, and the compiler will likely not be able to merge the identical parts. (Inlining makes this a lot harder.)

Which doesn't look like a big deal when you first look at it, until you notice:

When you use them inside templated functions like std::sort, the the compiler generates new code for each different lambda.

This can blow up the code size disproportionately.

bind, however, is typically is more resilient to such changes (although not immune to them).

To illustrate what I mean...

  1. Take the example below, compile it with GCC (or Visual C++), and note the output binary size.
  2. Try changing if (false) to if (true), and seeing how the output binary size changed.
  3. Repeat #1 and #2 after commenting out all except one of the stable_sorts in each part.

Notice that the first time, C++11 lambdas are slightly smaller; after that, their size blows up after each use (about 3.3 KB of code for each sort with VC++, similar with GCC), whereas the boost::lambda-based binaries barely change their sizes at all (it stays the same size for me when all four are included, to the nearest half-kilobyte).

#include <algorithm>
#include <string>
#include <vector>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp> // can also use boost::phoenix

using namespace boost::lambda;

struct Foo { std::string w, x, y, z; };

int main()
{
std::vector<Foo> v1;
std::vector<size_t> v2;
for (size_t j = 0; j < 5; j++) { v1.push_back(Foo()); }
for (size_t j = 0; j < v1.size(); j++) { v2.push_back(j); }
if (true)
{
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::w, var(v1)[_1]) < bind(&Foo::w, var(v1)[_2]));
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::x, var(v1)[_1]) < bind(&Foo::x, var(v1)[_2]));
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::y, var(v1)[_1]) < bind(&Foo::y, var(v1)[_2]));
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::z, var(v1)[_1]) < bind(&Foo::z, var(v1)[_2]));
}
else
{
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].w < v1[j].w; });
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].x < v1[j].x; });
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].y < v1[j].y; });
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].z < v1[j].z; });
}
}

Note that this is "trading size for speed"; if you're in a very very tight loop, it can involve an extra variable (because now it's using pointers-to-members).

However, this is nothing like the overhead std::function introduces (which is a virtual call), and even that is unmeasurable in many cases, so this shouldn't be a cause for concern.



Related Topics



Leave a reply



Submit