C++において、ラムダ式は便利な匿名関数であり、外部変数をキャプチャしてその内部で使用できます。これにより、ラムダ式は柔軟なプログラミングツールとなります。ただし、ラムダ式のパラメータのライフサイクルは特に注意すべき点であり、特にキャプチャおよびパラメータの伝送時にはそうです。
ラムダ式のパラメータのライフサイクル
ラムダ式のパラメータの寿命は、通常、他のC++関数と同様です。関数のパラメータは、関数呼び出し中に存在し、関数呼び出しが終了すると、パラメータの寿命は終了します。しかしながら、ラムダ式が外部変数にキャプチャする場合、パラメータの寿命はキャプチャ方法の影響も受けます。
キャプチャとパラメータのライフサイクルとの関係
2.1 外部変数の捕捉
C++のラムダ式は、外部変数を2つの方法でキャプチャできます。
- 値キャプチャ:値キャプチャによって、外部変数の値がラムダ関数内にコピーされ、そのコピーのライフサイクルはラムダ関数のライフサイクルによって制御されます。
- 参照獲得:参照獲得により、外部変数の参照は保持され、ラムダ内の参照は元の外部変数を示し、寿命はその外部変数に依存します。
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
捕捉された変数のライフサイクルは以下の通りです。
- 値によるキャプチャ:キャプチャされたとき、外部変数の値がラムダにコピーされます。そして、ラムダのライフサイクルが終わると、そのコピーが破棄されます。
- 参照によるキャプチャ:ラムダが外部変数への参照を持つ場合、外部変数はラムダの使用前に有効である必要があり、そうでないと未定義の動作が発生する可能性がある。
ラムダパラメータ
ラムダのパラメータは通常の関数パラメータと同様で、そのライフサイクルはラムダ関数内に限定されます。つまり、ラムダパラメータはラムダ呼び出し時に作成され、ラムダ呼び出しが終了すると、パラメータのライフサイクルも終了します。
auto lambda = [](int a, int b) {
std::cout << a + b << std::endl;
};
lambda(5, 10); // a和b在这里是lambda的参数
この例では、a
と b
はラムダ式のパラメータであり、ラムダ式の呼び出し時に作成され、実行終了後に破棄されます。
キャプチャした外部変数のライフサイクルに関する問題
キャプチャされた変数は、ラムダ関数外で有効に利用できるか。
- 値によるキャプチャ:ラムダ呼び出し後に外部変数が破棄されても、ラムダ内部は外部変数のコピーを保持します。したがって、外部変数はもう存在しなくても、ラムダ内部のコピーは安全に使用できます。
int x = 10;
auto lambda = [x]() { std::cout << x << std::endl; };
x = 20; // x 在lambda调用后修改
lambda(); // 打印10,捕获的是x的副本
- 参照によるキャプチャ:ラムダが外部変数の参照をキャプチャする場合、ラムダ内部でのその参照へのアクセスは外部変数のライフサイクルに依存します。外部変数がラムダの実行前に破棄されると、ハングリング参照の問題が発生し、未定義の動作につながる可能性があります。
int x = 10;
auto lambda = [&x]() { std::cout << x << std::endl; };
x = 20; // x 在lambda调用前修改
lambda(); // 打印20,捕获的是x的引用
ラムダの実行順序が確定しない場合、ラムダが実行される際にキャプチャされた外部変数が有効であることを保証することが非常に重要です。