1

のこの本体を考えてみましょうmain:

std::srand(std::time(nullptr));
while (std::rand());

驚いたことに、それが明確に定義されているかどうかについて、仕様、Google、またはこの Web サイトのいずれであっても、何も見つかりませんでした。スペックは:

N3485 § 6.5/4 [stmt.iter]は、条件について次のように述べています。

[ 注: 繰り返しステートメントの条件に関する要件は、6.4 で説明されています。— エンドノート]

しかし、6.4 を見てみると、このシナリオに言及しているものは何もありませんでした。理論的には、ループは事実上永遠に続く可能性がありますが、実際には、実行時間は通常 5 ミリ秒で、すべてのテスト実行で 1 回は 22 ミリ秒でした。

変化する (疑似) 乱数に基づいてループ終了条件を設定するのは、明確に定義された動作ですか? そうでない場合、それはどのような種類の動作ですか?

4

5 に答える 5

7

std::rand()繰り返しごとに呼び出され、その戻り値に応じてループが続くかどうかが決まります。

ここで未定義の動作を行う理由はありません。

こういうことをするのと変わらない

while (my_vector.empty());

なぜこのケースが特別だと思いますか?

于 2013-01-06T13:26:50.303 に答える
3

の振る舞い

while (std::rand());

確かに、明確に定義されています。つまり、組み込みの疑似乱数ジェネレーターの状態を、0 を返す状態に変更します。

ただし、コンパイラはこのループが最終的に終了すると想定する場合があるため ([intro.multithread]/24 によって)、遅延が認識されない場合や、遅延が発生した後にプログラムから何らかの目に見える効果が生じる場合があります。遅延の前に(恐ろしく賢いコンパイラを持っている場合)。

于 2013-01-06T14:13:44.813 に答える
1

「これは合法か」というケースについてはカバーしたと確信していますが、この特定の方法を使用してランダムな [1] 時間待機することが非常に良い考えであるかどうかはわかりません。

次のようなものを使用すると思います

int delay = constant + rand() * factor;
usleep(delay);

はるかに良い選択になります。これにより CPU 負荷が軽減され、定義された範囲が得られます。最初の無数の呼び出しで rand() がゼロになる保証はないため、遅延はかなり劇的に変化する可能性があります。

[1] srand() に適切に変化する数値が与えられたと仮定すると、「time()」がそれを達成するための最良の方法であるかどうかはわかりません。1 日に 1 回再初期化すれば問題ありませんが、同じ秒内に複数回開始するコードがある場合、それらはすべて同じシードを取得します。

于 2013-01-06T13:46:12.767 に答える
1

他の回答に追加すると、コンパイラがループが終了すると想定できるようにする標準の句の理由は、無限ループを未定義にするのではなく、コンパイラが決定できない状況でも最適化を実行できるようにするためです。ループが終了する場合。

例えばこんな状況で

while(rand()) f();

rand と f のどちらにも副作用がないことをコンパイラが判断できれば、rand が最終的に 0 を返すことを証明できなくても、コンパイラはループ全体を削除できます。

于 2013-01-07T15:56:11.377 に答える
-1

この場合、srand の初期化は常に同じであるため、while の動作は各実行で同じです。いくつかのランダムなデータを時間内に入れてみると、実行時間の変化を見ることができます。

于 2013-01-06T13:31:33.917 に答える