In C++, lambda expressions are convenient anonymous functions that can capture external variables and use them within their bodies. This makes lambdas a flexible programming tool. However, the lifetime of lambda expression parameters is an aspect that requires special attention, especially when capturing and passing parameters.
The lifecycle of parameters in lambda expressions
The lifetime of lambda expression parameters is typically the same as that of other C++ functions. Function parameters exist during the function call and end when the function call completes. However, because lambda expressions may capture external variables, the lifetime of the parameters can also be affected by the capturing method.
The relationship between capture and parameter lifecycle
2.1 Capturing External Variables
C++ lambda expressions allow capturing external variables in two ways:
- Value capturing: Through value capture, the values of external variables are copied into the lambda, and the lifecycle of these copies is controlled by the lifecycle of the lambda
- Closure: Through closure capturing, references to external variables are preserved; references within a lambda point to the original external variables, and their lifecycle depends on the external variables
int x = 10;
auto lambda_by_value = [x]() { std::cout << x << std::endl; }; // 捕获x的副本
auto lambda_by_reference = [&x]() { std::cout << x << std::endl; }; // 捕获x的引用
lambda_by_value(); // 打印10
lambda_by_reference(); // 打印10
The lifecycle of captured variables is as follows:
- By-value capture: When capturing, the values of external variables are copied into the lambda, and when the lambda’s lifecycle ends, these copies are destroyed
- Capture by reference: A lambda holding a reference to an external variable must have the external variable be valid before the lambda is used, otherwise it can lead to undefined behavior
2.2 Lambda Parameters
Lambda parameters are similar to regular function parameters, their lifecycle is limited to within the lambda function. That is, lambda parameters are created when the lambda is called and their lifecycle ends after the lambda call is completed.
auto lambda = [](int a, int b) {
std::cout << a + b << std::endl;
};
lambda(5, 10); // a和b在这里是lambda的参数
In this example, a
and b
are parameters of the lambda expression, they are created when the lambda is called and destroyed after the lambda execution ends
Lifecycle issues when capturing external variables
Whether captured variables can be valid outside of a lambda
- Capture by value: Even if external variables are destroyed after a lambda call, the lambda still holds a copy of the external variable. Therefore, the copy inside the lambda can be used safely, even if the external variable no longer exists.
int x = 10;
auto lambda = [x]() { std::cout << x << std::endl; };
x = 20; // x 在lambda调用后修改
lambda(); // 打印10,捕获的是x的副本
- By reference capture: If a variable is captured by reference, the lambda’s access to that reference depends on the lifetime of the external variable. If the external variable is destroyed before the lambda executes, this can lead to a dangling reference and undefined behavior.
int x = 10;
auto lambda = [&x]() { std::cout << x << std::endl; };
x = 20; // x 在lambda调用前修改
lambda(); // 打印20,捕获的是x的引用
It is very important to ensure that captured external variables remain valid when the lambda function executes if the order of execution of lambdas is uncertain