2016-08-04 9 views
2

私は最近、ほとんどの場合に動作するが、未定義の動作に依存しているコードベースのラムダを発見しました。ここでの例である:ローカルテンポラリをキャプチャするラムダ関数をキャッチ

#include <iostream> 
#include <thread> 

std::thread thread; 

void foo(int bar) 
{ 
    thread = std::thread([&]() { std::cout << bar << std::endl; }); 
} 

int main(int argc, char* argv[]) 
{ 
    foo(5); 
    thread.join(); 
} 

ローカルスコープ(バー)の変数を参照することによって捕捉され、後の時点でアクセスされることがある問題。不思議なことに、私たちのコンパイラ(GCC、Clang、MSVC)は、たとえ "警告:ローカル一時オブジェクトのアドレスを返す"として捕まえるのが簡単であっても、デフォルトでこれについて警告していません。上記のコンパイラがこれについて警告する方法はありますか?

+0

ローカル変数のアドレスを返すのは誰ですか? –

+0

「捕まえるのは簡単だ」と大胆な発言です。あなたのコードで 'std :: thread'を' magic_box'で置き換え、コンパイラがこれについてまだ警告するべきかどうかを教えてください。 –

+2

投稿したコードにUBはありません。すべての変数のライフタイムは、アクセスしても終了しません。 –

答えて

0

一時変数のアドレスを返していません。一時変数の参照渡しは問題ありません。もちろん、スレッドを参照して変数を渡すと、ソース関数が期限切れになり、最初に一時変数が渡された場合に予期しない結果になる可能性があります。

しかし、コンパイラはスレッドの作成とスレッドの順序は気にしません。人々はstd::threadの代わりに独自のスレッドライブラリを使用する可能性があるからです。コンパイラの観点からは、言語構造の妥当性を探し、[&](...){}は有効な構文です。

つまり、コンパイラがこの(実際に有用な)警告をキャッチする方法はありません。残念ながらそれはプログラマの責任です。 argvstd::stringオブジェクトにコピーし、値渡しすることができます。

+0

"一時変数の参照の受け渡しは正常です"しかし、ほとんどのプログラマは、アドレスをその参照に保存して後でアクセスするのは悪い方法だと認識しています。このようなコードを書くプログラマはごくわずかです。int * temp = nullptr; void foo(int&bar) { temp = &bar; } – bgp2000

+0

_ "一時変数の参照の受け渡しは正常です。"いいえ、そうではありません....あなたはスレッドがリファレンスを通してその変数にいつアクセスするかを知る方法がありません。 –

+0

@LightnessRacesinOrbit、あなたがdownvotedした文は「スレッド」の文脈にありません。しかし、一般に変数を関数に渡すことはOKです。「スレッド」に関しては、2番目のステートメントで、スレッドまたは標準関数への参照によって変数を渡すかどうかをコンパイラが知らないことをすでに明確にしています。問題は、コンパイラが警告を発するかどうかについてです。境界線の場合に警告を出すことができ、参照渡し変数はC++の非常に有効なイディオムであるため、答えは "いいえ"です。 – iammilind

1

これは最近私も気付いた。私は、関数の引数をキャプチャしていたことを実現しました。どこでも

このような場合、私はこのことについて警告を受けたいと思っていますが、多くの場合、キャプチャには何も問題はないという理由が考えられます。すぐにラムダを実行する限り、あなたは安全です。後で使用するために(ワーカースレッド内を含む)問題が発生する可能性があるので、それを保存するときだけです。

どちらのコンパイラもまだ十分に巧妙ではないか、またはその作者がこれについて警告しないことに決めました。

どのような場合でも、あなたのコードを警告する主流のコンパイラは認識していません。だから、本当に注意する必要があります。

+0

'どちらのコンパイラもまだ十分に巧妙ではありません。コンパイラは、スレッド構造ライブラリではなく、言語構造だけを理解できるため、この場合には巧妙ではありません。 -1、あなたは私の答えから同じことに少しでも飾りつけとあなた自身の「感情」で答えているからです。 – iammilind

+0

@ iammilind:私はあなたを「無責任に」怒らせず、私の答えはあなたと全く同じではありませんでした。一方、あなたが認めたように、あなたは投稿に載っていない人に基づいてそれをやっているので、あなたは "無責任"にダウン投票します。グリップを取得します。 –

+1

@iammilind:_ "この場合、コンパイラは言語構造だけを理解できるため、巧妙ではありません。スレッドライブラリではありません" _まったくナンセンス。まず第一に、threadingライブラリ_はcompiler_を使います。それは絶対にそれを理解することができます。第二に、コンパイラはラムダがここでUBであることを知るためにどのように使われるかについて何も知る必要はありません。 –

関連する問題