C++ 循环不变量(特别是“加速C&“x2B”和“x2B”的第3章)
我目前正在学习“加速C++”,刚刚在第3章中遇到了这个问题:C++ 循环不变量(特别是“加速C&“x2B”和“x2B”的第3章),c++,invariants,C++,Invariants,我目前正在学习“加速C++”,刚刚在第3章中遇到了这个问题: // invariant: // we have read count grades so far, and // sum is the sum of the first count grades while (cin >> x) { ++count; sum += x; } 作者随后解释说,不变量需要特别注意,因为当输入被读入x时,我们将读取count+1等级,因此不变量将不真实。类似地,当我们增
// invariant:
// we have read count grades so far, and
// sum is the sum of the first count grades
while (cin >> x) {
++count;
sum += x;
}
作者随后解释说,不变量需要特别注意,因为当输入被读入x
时,我们将读取count+1
等级,因此不变量将不真实。类似地,当我们增加计数器时,sum
将不再是最后一次计数分数的总和(如果您没有猜到,它是计算学生分数的传统程序)
我不明白为什么这很重要。当然,对于任何其他循环,类似的说法都是正确的?例如,这是本书的第一个while
循环(稍后填写输出):
//不变量:到目前为止,我们已经编写了r行
while(r!=行){
//写入一行输出
std::cout从您的描述中,听起来作者在胡说八道。是的,在指令之间,不变量暂时变得不真实,但每当您执行类似的非原子操作时,就会发生这种情况。只要没有任何明显的断点,可能导致不变量不正确,并且程序处于错误状态状态一致,你很好
在这种情况下,唯一可能发生的方法是,如果std::cout在不变量不真实的情况下抛出异常,那么您会在某个地方捕获该异常,但会在错误的状态下继续执行。在我看来,作者过于迂腐。因此,只要您没有任何break/continue语句出现在错误的位置,或者没有异常出现你没问题。我怀疑很多人会费心关注你的示例代码,因为它太简单了。我相信这本书是指while循环停止的方式。在第二种情况下,很容易看到循环将在“r”增加到等于“rows”时停止因为大多数C++中的计数都是零,所以这很可能为每行输出一行。
另一方面,第一个示例是对cin对象上的“>>”使用运算符重载。只要此函数不返回零,while循环将继续。在输入关闭之前,该运算符重载不会返回此值
您可以按什么键使“cin>>”返回0?否则循环将永远不会结束。您需要确保不会创建这样的循环
需要在条件之外添加一行来停止循环。请查找“break”和“continue”语句。一般来说,不变量只适用于循环的迭代之间。(至少我是这样理解的!)
一般情况如下:
[invariant true];
while (keep going) {
[state transformation];
[invariant true];
}
但是在状态转换期间,不变量不一定成立
作为一个单独的风格说明:如果你想成为一名超级程序员,不要把不变量留在注释中,让它们成为断言
// Loop invariant: x+y = -4
for (int x = 0; x < 10; x++) {
[do something];
assert(x+y == -4); // Loop invariant here!
}
//循环不变量:x+y=-4
对于(int x=0;x<10;x++){
[做点什么];
断言(x+y==-4);//此处循环不变!
}
这样您就有了自检代码。这在异常安全环境中非常有趣/重要
考虑以下场景:
- “count”是一个用户定义的类,具有重载的
运算符+++
- 重载的
运算符+++
引发异常
- 稍后在循环外部捕获异常(即,循环看起来像现在一样,没有try/catch)
在这种情况下,循环不变量不再成立,循环中发生的所有事情的状态都有问题。行是否已写入?计数是否已更新?总和是否仍然正确
一些额外的保护(以临时变量的形式保存中间值和一些try/catch)需要确保即使在抛出异常时,所有内容都保持一致。这本书似乎比它应该做的要复杂得多。我真的不认为用不变量解释循环是一件好事。这有点像用量子物理解释加法
作者随后解释说,不变量需要特别注意,因为当输入被读入变量x时,我们将读取计数+1级,因此不变量将不真实。同样,当我们增加计数器时,变量和将不再是最后计数级的和(如果你没有猜到,这是计算学生分数的传统程序)
首先,不变量是不清楚的。如果不变量是“在的迭代结束时,
循环,我们已经阅读了计数
等级和求和
”,那么在我看来这是正确的。不变量没有明确指定,所以谈论它何时被尊重和不被尊重都没有意义
如果不变量是“在<代码>循环的任何迭代点,而<代码>循环,我们已经读过…`,那么严格地说,该不变量将不是真的。就循环而言,我认为不变量应该是指在循环的开始、结束或固定点处存在的状态
我没有那本书,我也不知道事情是否得到澄清,但似乎使用不变量是错误的。如果它们的不变量不是真的,为什么还要麻烦使用一个呢
我认为你不应该太担心这个问题。只要你了解这些循环是如何工作的,你就可以了。如果你想通过不变量来理解它们,你可以,但是你必须注意你选择的不变量。不要选择一个不好的,否则它就达不到目的。你应该选择一个易于编写代码的不变量尊重它,而不是选择一个随机的然后努力编写尊重它的代码,并且绝对不要选择一个模糊的然后编写具有
// Loop invariant: x+y = -4
for (int x = 0; x < 10; x++) {
[do something];
assert(x+y == -4); // Loop invariant here!
}
// invariant: we have written r rows so far
int r = 0; // this is also important!
while (r != rows) {
// write a row of output
std::cout << std::endl;
++r;
}
while (cin >> x) {
++count;
}
rows = NROWS;
r = 0;
while (r != rows) {
// write a row of output
std::cout << std::endl;
++r;
}