一个永远不终止的程序是一个有效的C++程序吗?

16

是否需要一个程序来终止?换句话说,永远运行的程序在技术上是未定义行为吗?注意,这不是关于空循环的问题。讨论的是那些永远执行“操作”(即可观察行为)的程序。

例如,像这样的内容:

int main()
{
    while (true)
    {
        try
        {
            get_input(); // calls IO
            process();
            put_output(); // calls IO, has observable behavior

            // never break, exit, terminate, etc
        } catch(...)
        {
            // ignore all exceptions
            // don't (re)throw
            // never go out of loop
        }
    }
}

这更多是一个学术问题,因为实证上,所有正常的编译器都将为上述程序生成预期的代码(当然,假设没有其他UB来源)。当然,有很多程序永远不会终止(操作系统、嵌入式系统、服务器等)。但是标准有时候很古怪,所以才会有这个问题。
旁观者:许多(一些?)算法定义要求算法必须终止,即一系列永远不会终止的操作不被视为算法。
旁观者。停机问题指出,不存在一种算法能够确定任意程序是否在给定输入下结束。然而,对于这个特定的程序,由于没有任何分支导致离开main函数,编译器可以轻松确定程序永远不会结束。但这与问题的语言法律无关。

评论不适合进行长时间的讨论;此对话已被移至聊天室 - Samuel Liew
2个回答

16
C++标准中没有要求程序或任何给定线程终止的内容。最接近的是[intro.progress]p1,其中提到:
实现可以假设任何线程最终都会执行以下操作之一: - 终止, - 调用库I/O函数, - 通过易失性glvalue进行访问,或 - 执行同步操作或原子操作。
只要有一些可观察的行为,或者只要它花费所有时间阻塞在I/O操作或另一个阻塞的库调用上,这就不适用,并且程序是有效的(假设它满足所有其他有效性标准)。

“一个I/O操作或另一个阻塞库调用” - 标准非常明确,只列出了I/O操作。为什么您要添加“或另一个阻塞库调用”?此外,该I/O操作已经包含在您早期提到的 “某些可观察行为”中。 - MSalters
1
@MSalters std::mutex::lock() 是一个同步操作的库调用,属于第四个要点。因此,并不是只有 I/O 调用被提到了。 - Igor Tandetnik
如果程序一直停留在“输入”状态,但却没有得到任何输入,那么这是否算作可观察的情况还有待商榷。 - Daniel H

4

是的。来自[intro.progress]

实现可以假定任何线程最终都会执行以下操作之一:

  • 终止,
  • 调用库I/O函数,
  • 通过易失性glvalue进行访问,或者
  • 执行同步操作或原子操作。

[注意:这旨在允许编译器转换,例如删除空循环,即使无法证明终止。—注解]


我认为最好加上一点描述,说明该程序进行输入/输出操作。 - KamilCuk
只要OP示例中的“get_input”和“put_output”函数“调用库I/O函数”,即使程序不终止,它也应该是有效的? - Some programmer dude
@Someprogrammerdude 或访问一个 volatile 或 atomic 值,是的。 - Caleth
1
编译器不知道 - 这并不重要。从语言层面来看,编译器可能知道也可能不知道,问题在于它是否有效。 - KamilCuk
@ Damon 注释不是规范性的;我认为“实现可以假设”意味着“否则行为未定义”。 - Daniel H
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接