3 回答
TA贡献1805条经验 获得超9个赞
有人能很好地解释为什么这是必要的吗?
正如N 1509正确指出的那样,当前的草案本质上给出了6.8.5p6中无限循环的未定义行为。这样做的一个主要问题是,它允许代码在一个潜在的非终止循环中移动。例如,假设我们有以下循环,其中Count和Count 2是全局变量(或已获取它们的地址),而p是局部变量,其地址尚未被接受: for (p = q; p != 0; p = p -> next) { ++count;}for (p = q; p != 0; p = p -> next) { ++count2;}
这两个循环能被合并替换为下面的循环吗? for (p = q; p != 0; p = p -> next) { ++count; ++count2;}
如果没有6.8.5p6中对无限循环的特殊分配,这将是不允许的:如果第一个循环没有因为q指向循环列表而终止,那么原始循环就不会写到Count 2。因此,它可以与访问或更新Count 2的另一个线程并行运行。对于转换后的版本来说,这已经不再安全了,尽管存在无限循环,但它仍然可以访问Count 2。因此,转换可能会引入数据竞争。
在这种情况下,编译器很难证明循环终止;它必须理解Q指向一个非循环列表,我认为这超出了大多数主流编译器的能力,而且没有完整的程序信息通常是不可能的。
非终止循环所施加的限制是对编译器无法证明终止的终止循环的优化的限制,也是对实际非终止循环的优化的限制。前者比后者更常见,而优化往往更有趣。
显然还有带有整数循环变量的for-循环,编译器很难证明终止,因此编译器很难在没有6.8.5p6的情况下重构循环。甚至像 for (i = 1; i != 15; i += 2)
或 for (i = 1; i <= 10; i += j)
似乎很难处理。(在前一种情况下,需要一些基本的数论来证明终止,在后一种情况下,我们需要了解j的可能值。对无符号整数的环绕可能会进一步使这种推理复杂化。)
这个问题似乎适用于几乎所有的循环重构转换,包括编译器并行化和缓存优化转换,这两种转换都很可能变得重要,而且对数值代码通常也很重要。这似乎会变成一笔巨大的成本,以便能够以最自然的方式编写无限循环,特别是因为我们大多数人很少有意识地编写无限循环。
TA贡献1830条经验 获得超3个赞
这是为了允许编译器转换-mdash;,例如删除空循环,即使终止不能被证明。
while (complicated_condition()) { x = complicated_but_externally_invisible_operation(x);}complex_io_operation();cout << "Results:" << endl;cout << x << endl;
complex_io_operation
complex_io_operation()
TA贡献1852条经验 获得超1个赞
main
- 3 回答
- 0 关注
- 507 浏览
添加回答
举报