Understanding Lambda Capture Modes in C++

C++ lambdas allow you to capture variables from their surrounding scope, enabling powerful and flexible behavior. There are several ways variables can be captured, each with its own syntax and purpose.

1. Capture by Value: [=] or [x]

  • Syntax: [=] captures all automatic variables used in the lambda by value (i.e., makes a copy).
  • Syntax: [x] captures only x by value.
  • Use when: You want the lambda to access, but NOT modify, external variables.
int x = 10;
auto f = [x]() { std::cout << x << "\n"; }; // captures x by value (a copy)
x = 20;
f(); // prints 10

2. Capture by Reference: [&] or [&x]

  • Syntax: [&] captures all automatic variables used in the lambda by reference.
  • Syntax: [&x] captures only x by reference.
  • Use when: You want the lambda to be able to modify external variables.
int x = 10;
auto f = [&x]() { x = 15; };
f();
std::cout << x << "\n"; // prints 15

3. Mixed Capture

You can mix capture types for different variables:

int x = 1, y = 2;
auto f = [x, &y]() { std::cout << x << " " << y << "\n"; };
  • Here, x is captured by valuey by reference.

4. Default Plus Specific

You can set a default and override for specific variables:

int x = 3, y = 4;
auto f = [=, &y]() { std::cout << x + y << "\n"; }; // x by value, y by reference

5. Capture Everything by Value or Reference

  • [=]: all used automatic variables by value.
  • [&]: all used automatic variables by reference.

6. C++14 Generalized Capture (Init Capture)

You can initialize new variables in the capture list (C++14 and above):

int val = 5;
auto f = [z = val + 2]() { std::cout << z << "\n"; }; // captures a new variable z = 7

Example Code: Exploring Capture Modes

Try the following code to experiment with captures:

#include <iostream>

int main() {
    int a = 1, b = 2;

    // Capture by value
    auto byValue = [a]() { std::cout << "by value: " << a << "\n"; };
    a = 10;
    byValue(); // prints 1

    // Capture by reference
    auto byRef = [&b]() { b = 20; };
    byRef();
    std::cout << "by reference: " << b << "\n"; // prints 20

    // Mixed capture
    int c = 3, d = 4;
    auto mixed = [c, &d]() { std::cout << "mixed: " << c << ", " << d << "\n"; };
    d = 40;
    mixed(); // prints 3, 40

    // Init capture (C++14+)
    int e = 5;
    auto initCap = [x = e + 5]() { std::cout << "init capture: " << x << "\n"; };
    initCap(); // prints 10
}

Summary Table of Capture Types

Capture SyntaxCapturesCan Modify?
[=]All by valueNo
[&]All by referenceYes
[x]Only x, by valueNo
[&x]Only x, by referenceYes
[=, &x]All by value, x by referencex only
[&, x]All by reference, x by valueAll but x
[x = y + 1]Initializes x inside the lambda (C++14+)x only

Experiment with these different capture modes to get a deeper understanding of how lambdas interact with their surrounding variables in C++.

If you are new to Lambda check my Lambda post to know about them.

Leave a Comment

Your email address will not be published. Required fields are marked *