ラムダ式の変数キャプチャ部分の性質について混乱しています。
void f1();
std::function<int()> f2;
int main() {
f1();
std::cout<<f2()<<endl;
}
void f1() {
int x;
f2 = [&]() {
return x;
};
}
呼び出されるx
前に解体されていませんか?f2
はい。未定義の動作を正常に呼び出しました。考えられる結果の 1 つは、x の値を取得することです。もう 1 つは、コンピューターがハード ドライブをフォーマットしたり、プログラムがクラッシュしたり、コンピューターがロボットのパン職人暗殺者に変身してカップケーキを食べさせたりして、セリアック病にかかっていると誤解することです。
これの安全な変形は次のようになります:
int main() {
f1(7);
std::cout<<f2()<<endl;
}
void f1(int x) {
std::shared_ptr<int> spX( new int(x) );
f2 = [=]() {
return *spX;
};
}
また
void f1(int x) {
f2 = [=]() {
return x;
};
}
(int の場合、値で格納しない理由はほとんどありません。より複雑な型の場合は、不必要にコピーすることを避けたい場合があります)。
上記のコメントは、これをより面白い方法で説明していることに注意してください。
現在、一部のコンパイラは、この種の未定義の動作を正確にキャッチするためにスタックをデクリメントするときに、特別な値でスタックにマークを付けます (キャッチとは、プログラマにとってより明確にすることを意味します)。しかし、ほとんどの場合、C++ で未定義の動作を呼び出すことは可能です。
x は f2 が呼び出される前に分解されていませんか?
はい、そうです。これは、return x
が未定義の動作を引き起こすダングリング参照を評価することを意味します。
この場合、値でキャプチャすることをお勧めします。
f2 = [x]() { return x; }