C++ Class lambdas and capture of this


Example

A lambda expression evaluated in a class' member function is implicitly a friend of that class:

class Foo
{
private:
    int i;
    
public:
    Foo(int val) : i(val) {}
    
    // definition of a member function
    void Test()
    {
        auto lamb = [](Foo &foo, int val)
        {
            // modification of a private member variable
            foo.i = val;
        };
        
        // lamb is allowed to access a private member, because it is a friend of Foo
        lamb(*this, 30);
    }
};

Such a lambda is not only a friend of that class, it has the same access as the class it is declared within has.

Lambdas can capture the this pointer which represents the object instance the outer function was called on. This is done by adding this to the capture list:

class Foo
{
private:
    int i;
    
public:
    Foo(int val) : i(val) {}
    
    void Test()
    {
        // capture the this pointer by value
        auto lamb = [this](int val)
        {
            i = val;
        };
        
        lamb(30);
    }
};

When this is captured, the lambda can use member names of its containing class as though it were in its containing class. So an implicit this-> is applied to such members.

Be aware that this is captured by value, but not the value of the type. It is captured by the value of this, which is a pointer. As such, the lambda does not own this. If the lambda out lives the lifetime of the object that created it, the lambda can become invalid.

This also means that the lambda can modify this without being declared mutable. It is the pointer which is const, not the object being pointed to. That is, unless the outer member function was itself a const function.

Also, be aware that the default capture clauses, both [=] and [&], will also capture this implicitly. And they both capture it by the value of the pointer. Indeed, it is an error to specify this in the capture list when a default is given.

C++17

Lambdas can capture a copy of the this object, created at the time the lambda is created. This is done by adding *this to the capture list:

class Foo
{
private:
    int i;
    
public:
    Foo(int val) : i(val) {}
    
    void Test()
    {
        // capture a copy of the object given by the this pointer
        auto lamb = [*this](int val) mutable
        {
            i = val;
        };
        
        lamb(30); // does not change this->i
    }
};