C++ Capture by value


Example

If you specify the variable's name in the capture list, the lambda will capture it by value. This means that the generated closure type for the lambda stores a copy of the variable. This also requires that the variable's type be copy-constructible:

int a = 0;

[a]() {
    return a;   // Ok, 'a' is captured by value
};
C++14
auto p = std::unique_ptr<T>(...);

[p]() {         // Compile error; `unique_ptr` is not copy-constructible
    return p->createWidget(); 
};

From C++14 on, it is possible to initialize variables on the spot. This allows move only types to be captured in the lambda.

C++14
auto p = std::make_unique<T>(...);

[p = std::move(p)]() {
    return p->createWidget(); 
};

Even though a lambda captures variables by value when they are given by their name, such variables cannot be modified within the lambda body by default. This is because the closure type puts the lambda body in a declaration of operator() const.

The const applies to accesses to member variables of the closure type, and captured variables that are members of the closure (all appearances to the contrary):

int a = 0;

[a]() {
    a = 2;      // Illegal, 'a' is accessed via `const`

    decltype(a) a1 = 1; 
    a1 = 2; // valid: variable 'a1' is not const
};

To remove the const, you have to specify the keyword mutable on the lambda:

int a = 0;

[a]() mutable {
    a = 2;      // OK, 'a' can be modified
    return a;
};

Because a was captured by value, any modifications done by calling the lambda will not affect a. The value of a was copied into the lambda when it was constructed, so the lambda's copy of a is separate from the external a variable.

int a = 5 ; 
auto plus5Val = [a] (void) { return a + 5 ; } ; 
auto plus5Ref = [&a] (void) {return a + 5 ; } ; 

a = 7 ; 
std::cout << a << ", value " << plus5Val() << ", reference " << plus5Ref() ;
// The result will be "7, value 10, reference 12"