1

考虑这个身体main

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

令人惊讶的是,无论是在规范中、在 Google 上还是在这个网站上,我都找不到任何关于这是否定义明确的信息。至于规格:

N3485 § 6.5/4 [stmt.iter]说明了这种情况:

[注:迭代语句中的条件要求见6.4。——尾注]

但是,通过 6.4,我没有看到任何与这种情况相关的内容。理论上,循环实际上可以永远持续下去,但在实践中,我通常有 5 毫秒的运行时间,所有测试运行中的一次是 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()”是实现这一目标的最佳方式。如果您每天重新初始化一次很好,但如果您的代码在同一秒内启动多次,它们都会得到相同的种子。

于 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 回答