C++ lambda capture this vs capture by reference

49,328

Solution 1

For the specific example you've provided, capturing by this is what you want. Conceptually, capturing this by reference doesn't make a whole lot of sense, since you can't change the value of this, you can only use it as a pointer to access members of the class or to get the address of the class instance. Inside your lambda function, if you access things which implicitly use the this pointer (e.g. you call a member function or access a member variable without explicitly using this), the compiler treats it as though you had used this anyway. You can list multiple captures too, so if you want to capture both members and local variables, you can choose independently whether to capture them by reference or by value. The following article should give you a good grounding in lambdas and captures:

https://crascit.com/2015/03/01/lambdas-for-lunch/

Also, your example uses std::function as the return type through which the lambda is passed back to the caller. Be aware that std::function isn't always as cheap as you may think, so if you are able to use a lambda directly rather than having to wrap it in a std::function, it will likely be more efficient. The following article, while not directly related to your original question, may still give you some useful material relating to lambdas and std::function (see the section An alternative way to store the function object, but the article in general may be of interest):

https://crascit.com/2015/06/03/on-leaving-scope-part-2/

Solution 2

Here is a good explanation of what &, this and the others indicate when used in the capture list.

In your case, assuming that all what you have to do is calling a member function of the instance that is actually referenced by the this of the method that is currently executing, put this in your capture list should be enough.

Solution 3

Capturing this and capturing by reference are two orthogonal concepts. You can use one, both, or none. It doesn't make sense to capture this by reference but you can capture other variables by reference while capturing this by value.

Solution 4

It's not a clear-cut situation where on is better than the other. Rather, the two (at least potentially) accomplish slightly different things. For example, consider code like this:

#include <iostream>

    class foo { 
        int bar = 0;
    public:
        void baz() {
            int bar = 1;
            auto thing1 = [&] { bar = 2; };
            auto thing2 = [this] { this->bar = 3; };

            std::cout << "Before thing1: local bar: " << bar << ", this->bar: " << this->bar << "\n";    
            thing1();
            std::cout << "After thing1: local bar: " << bar << ", this->bar: " << this->bar << "\n";
            thing2();
            std::cout << "After thing2: local bar: " << bar << ", this->bar: " << this->bar << "\n";
        }
    };


int main() { 
    foo f;
    f.baz();
}

As you can see, capturing this captures only the variables that can be referred to via this. In this case, we have a local variable that shadows an instance variable (yes, that's often a bad idea, but in this case we're using it to show part of what each does). As we see when we run the program, we get different results from capturing this vs. an implicit capture by reference:

Before thing1: local bar: 1, this->bar: 0
After thing1: local bar: 2, this->bar: 0
After thing2: local bar: 2, this->bar: 3

As to the specifics of capturing everything vs. only what you use: neither will capture any variable you don't use. But, since this is a pointer, capturing that one variable gives you access to everything it points at. That's not unique to this though. Capturing any pointer will give you access to whatever it points at.

Share:
49,328
vikky.rk
Author by

vikky.rk

Updated on July 30, 2020

Comments

  • vikky.rk
    vikky.rk almost 4 years

    If I need to generate a lambda that calls a member function, should I capture by reference or capture 'this'? My understanding is that '&' captures only the variables used, but 'this' captures all member variable. So better to use '&'?

    class MyClass {
      public:
        int mFunc() {
          // accesses member variables
        }
    
        std::function<int()> get() {
          //return [this] () { return this->mFunc(); };
          //  or
          //return [&] () { return this->mFunc(); };
        }
    
      private:
        // member variables
    }