Herb Sutterの説得力のある講義Not your father's C++に触発されて、私はMicrosoftのVisual Studio 2010を使ってC++の最新バージョンをもう一度見直すことにしました。私がC++ 11がよく知られている上方funarg問題をどのように解決したか聞いていなかったので、 "安全"です。私が知ることから、C++ 11はこの問題を解決するために何もしないので、結果的に「安全」ではありません。C++でlambdaを使用した非決定的な破損11
ローカル変数は、関数が返された後も存在しなくなるスタックフレームに割り当てられ、割り当てられたメモリへのダングリングポインタを返すため、ローカル変数への参照を返したくない非決定的なデータ破損を引き起こします。 CおよびC++コンパイラはこれを認識し、ローカルへの参照またはポインタを返そうとすると警告します。たとえば、このプログラム:
int &bar() {
int n=0;
return n;
}
は警告を発するようにVisual Studioの2010年が発生します。
warning C4172: returning address of local variable or temporary
しかし、C++ 11でラムダは参照することにより、ローカル変数をキャプチャしていることを返すが容易になりますその結果、等価なダングリングポインタが生成されます。ローカル変数n
をキャプチャし、それを返すラムダ関数を返す、次の機能foo
を考えてみましょう:
#include <functional>
std::function<int()> foo(int n) {
return [&](){return n;};
}
この無害に見える機能は、メモリ安全ではないと破損したデータのソースです。一つの場所にラムダを取得するには、この関数を呼び出した後、ラムダを呼び出すと、別の場所でその戻り値を印刷することは私のために、この出力を与える:
1825836376
また、Visual Studioの2010年には警告を与えません。
これは本当に深刻なデザイン上の欠陥のようです。最も単純なリファクタリングでさえ、ラムダクロススタックフレームを作成し、非決定的なデータ破損を静かに導入することができます。しかし、この問題に関する貴重な情報はほとんどありません(例えば、StackOverflow上の "upwards funarg"とC++はヒットしません)。人々はこれを知っていますか?誰かが解決策に取り組んでいるのか、回避策を記述していますか?
警告の欠如が唯一である:それは本当にあなたがC++
ビーイングは、あなたのラムダ例では、簡単な変更は、あなたのラムダの例では、完全に安全なものになる、と言わを使用するシナリオに適合しません私がここに見る問題ですが、それはまさに言語の設計上の欠陥ではありません。 –
私はこれに対する解決策はありませんが、C/C++を使って自分自身を本当に傷つける別の方法だと思います - "大きな力をもって、大きな責任を負う" D – Carsten
@CarstenKönig、OPのおかげで、 :) –