Herb Sutter の説得力のある講義Not your Father's C++に触発されて、Microsoft の Visual Studio 2010 を使用して C++ の最新バージョンをもう一度見てみることにしました。 ++11 はよく知られている上向きの funarg 問題を解決しました。私が知る限り、C++11 はこの問題を解決するために何もしていないため、「安全」ではありません。
関数が戻った後に存在しなくなるスタックフレームにローカル変数が割り当てられているため、ローカル変数への参照を返したくないため、関数は割り当てられたメモリへのダングリングポインターを返します。 -決定論的なデータの破損。C および C++ コンパイラはこれを認識しており、ローカルへの参照またはポインターを返そうとすると警告します。たとえば、このプログラム:
int &bar() {
int n=0;
return n;
}
Visual Studio 2010 で次の警告が表示されます。
warning C4172: returning address of local variable or temporary
ただし、C++11 のラムダを使用すると、参照によってローカル変数をキャプチャしてその参照を返すことが容易になり、結果として同等のダングリング ポインターが生成されます。foo
ローカル変数をキャプチャして返すラムダ関数を返す次の関数を考えてみましょうn
。
#include <functional>
std::function<int()> foo(int n) {
return [&](){return n;};
}
この無害に見える関数は、メモリが安全ではなく、破損したデータの原因となります。この関数を呼び出してラムダをある場所で取得し、ラムダを呼び出してその戻り値を別の場所に出力すると、次の出力が得られます。
1825836376
さらに、Visual Studio 2010 では警告が表示されません。
これは、言語の非常に深刻な設計上の欠陥のように見えます。最も単純なリファクタリングでさえ、ラムダ クロス スタック フレームを作成し、暗黙のうちに非決定論的なデータ破損を導入する可能性があります。しかし、この問題に関する貴重な情報はほとんどないようです (たとえば、StackOverflow で "upwards funarg" や C++ を検索してもヒットしません)。人々はこれに気づいていますか?誰かが解決策に取り組んでいるか、回避策を説明していますか?