2017-05-17 5 views
5

今日、私はC++ 11ラムダで非常に直感的ではない動作に遭遇しました。問題のコードは次のとおりです。ローカル変数をキャプチャするラムダを返す

#include <stdio.h> 

auto sum(int x) { 
    return [&x](int y) { 
     return x + y; 
    }; 
} 

int main() { 
    int a = sum(2)(3); 
    printf("%d\n",a); 
} 

5を印刷する代わりに、これはぎこちないものを表示します。実際、少なくともGCCの私のバージョンでは、-O2最適化フラグをオンにすると、実際には5が出力されます。出力はコンパイラの最適化レベルに依存するため、未定義の動作です。しばらくすると、私は何が起こっているのか理解していると思う。

関数sumを呼び出すと、引数xに対応するスタック変数が2に設定され、関数sumが返されます。このスタック変数は、コンパイラが次のコードを実行するために必要なものによって上書きされる可能性がありますラムダが最終的に実行されるまでに、xがもはや保持していなかった場所で、プログラムは任意の整数に3を加えます。

C++でカリングを行うためのエレガントな方法はありますか?変数が正しく取得されることを保証しますか?

+4

値 '[=] 'で取り込みます。 – Galik

+0

ありがとう!それは私の予想以上に簡単でした。 –

+2

ちょうど読者のために、これはC++ 14ではなく、C++ 11です。関数の戻り値の型控除がC++ 14で追加されました。 – cdhowie

答えて

8

int xの寿命は限られています。自動ストレージ変数(「スタック」と呼ばれるもの)への参照は、変数の存続期間にわたってのみ有効です。この場合、変数が存在するスタックフレーム(スコープ)の終わりまで、または関数引数の関数まで。

[&]は、this(使用されている場合、または暗黙的に使用されている場合は値によって取り込まれます)を除いて、参照によって(「ローカル」)変数をキャプチャします。 [=]は、上記の変数を値で取得します。 [x]は明示的にxをキャプチャし、[&x]を明示的にキャプチャします。 C++ 17では[*this]も動作します。

[x=std::move(x)]または[blah=expression]もあります。

一般に、ラムダが現在のスコープよりも長生きする場合は、[&]を使用しないでください:キャプチャするものについて明示してください。

+0

精巧な答えをありがとう。私がC++をカリングすることを含む多くの答えは、私が理解できない多くのテンプレートコードを持っていたので、ちょうど試し始めました。今私は自分がやっていることをよく知っています。 –

関連する問題