C 11 ラムダでの参照のキャプチャ
C では、ラムダ式は、それを囲んでいるスコープから変数をキャプチャできます。ただし、キャプチャ方法によって、変数に参照によってアクセスするか値によってアクセスするかが決まります。次のコードを考えてみましょう:
<code class="cpp">#include <functional> #include <iostream> std::function<void()> make_function(int& x) { return [&]{ std::cout << x << std::endl; }; } int main() { int i = 3; auto f = make_function(i); i = 5; f(); }</code>
このコードは、[&] 構文を使用して参照によって変数 x をキャプチャします。このプログラムが未定義の動作を呼び出すことなく 5 を出力することを保証するかどうかという疑問が生じます。
答え: はい
コードは正しく動作することが保証されています。基礎となる標準の文言を調べる前に、このコードが C 委員会の意図どおりに機能することに注意することが重要です。しかし、C 11 標準の当初の文言はこの点に関して不明確であったため、説明を提供するために CWG 2011 号が提起されました。この問題は、C 標準の進行中の開発で対処されています。
標準の説明
C 標準の [expr.prim.lambda]/17 によると、コピーによってキャプチャされたエンティティを参照する id 式のみが、ラムダ クロージャ タイプのメンバー アクセスに変換されます。参照によってキャプチャされたエンティティを参照する ID 式はそのまま残され、外側のスコープで示されるのと同じエンティティを示し続けます。
上記のコードでは、キャプチャされたエンティティは make_function 関数のパラメータ x です。 、これはラムダの到達範囲内にあります。したがって、ラムダ式内の参照 x は、main 関数で宣言された元の変数を参照します。
最初は、make_function 関数が戻った後、x が有効期間外で参照されることが問題のように見えるかもしれません。ただし、有効期間外に参照を参照できるシナリオは限られています。一般に、参照はスコープ内で宣言されるか、クラスのメンバーであるかのいずれかです。この場合、クラス自体はその有効期間内に存在する必要があります。
したがって、標準では有効期間外での参照の使用を明示的に禁止していません。この抜け穴により、ラムダ式での参照による参照のキャプチャがサポートされるようになりました。
CWG Issue 2012 と今後の明確化
CWG Issue 2012 は、この見落としに対処するために提起されました。特定の状況下では、参照が存続期間外に参照される可能性があること。この問題の解決により、参照の参照によるラムダ キャプチャの仕様が誤って影響を受けました。ただし、この回帰は C 17 のリリースまでに修正される予定です。
以上がC 11 ラムダは、未定義の動作を呼び出さずに参照をキャプチャできますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。