程序永远不会终止有效的C ++程序吗?


15

是否需要终止程序?换句话说,是一个在技术上永远无法运行的程序吗?请注意,这与空循环无关。谈论永远做“东西”(即可观察到的行为)的程序。

例如这样的事情:

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的分支,因此编译器可以轻松确定该程序永远不会结束。但是,这是无关紧要的,因为问题是语言律师。


评论不作进一步讨论;此对话已转移至聊天
塞缪尔·柳

Answers:


15

在C ++标准中,没有什么要求程序或任何给定的线程终止。最接近的是[intro.progress] p1,它表示

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

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

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

只要最终出现某种可观察到的行为,或者只要它将所有时间都花在了I / O操作或另一个阻塞库调用上,就不适用,并且该程序是有效的(假定它满足所有其他有效性标准)。


“一个I / O操作或另一个阻塞库调用”-该标准非常清楚,仅列出了I / O操作。为什么要添加“或另一个阻止库调用”?同样,该I / O操作已包含在您先前的“ 某些可观察到的行为”中。
MSalters

1
@MSalters std::mutex::lock()是一个库调用,它是一个同步操作,属于第四个项目符号。因此,仅提及I / O调用是不正确的。
伊戈尔·坦德尼克

如果它卡在input上,但是什么也没得到,是否算是可观察的就值得商bat。
Daniel H

4

是。从[intro.progress]

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

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

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


我认为建议使用该程序执行I / O的简短描述。
KamilCuk

因此,只要OP示例中的get_inputand put_output函数“调用库I / O函数”,则该程序即使没有终止也应该有效。
一些程序员花花公子

@Someprogrammerdude或访问一个volatile或原子值,是的
Caleth

当没有当前的内存模型时,对c ++ 11之前的标准感到好奇。
bolov

1
compiler does not know-没关系。从语言层的角度来看,编译器可能知道也可能不知道-问题是在任何情况下它是否有效。
KamilCuk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.