我正在通过阅读Stroustrup的"使用C++的原理和实践"来学习C++.
在关于前置和后置条件的部分中,有以下函数示例:
int area(int length, int width) // calculate area of a rectangle; // pre-conditions: length and width are positive // post-condition: returns a positive value that is the area { if (length<=0 || width <=0) error("area() pre-condition"); int a = length*width; if (a<=0) error("area() post-condition"); return a; }
困扰我的是关于这段代码的任务:
找到一对值,以便此版本区域的前置条件成立,但后置条件不会.
是否存在整数的可能值,前置条件是可以的但后置条件不是?
是否存在整数的可能值,前置条件是可以的但后置条件不是?
是的,有许多输入值,可能导致后置条件失败.如果是
int a = length*width;
溢出正int
范围(std::numeric_limits
)并且编译器实现为这种情况产生负值.
正如其他人在他们的回答中所指出的length*width
那样,超出范围的]0-std::numeric_limits
情况实际上是未定义的行为,而后置条件只是无用的,因为可能需要预期任何值a
.
解决这个问题的关键点在@Deduplicator的回答中给出,前提条件需要改进.
作为Bjarne Stroustrup给出这个例子的理由的长矛:
我假设他想指出这种未定义的行为可能会导致后置条件中出现意外的负值,并且对于使用前置条件检查的天真假设会产生令人惊讶的结果.
不,在标准C++的已定义行为的范围内,没有任何值会违反后置条件.但是,有些值仍然可以使函数表现不正确,即值太大而其产品不适合整数.尝试通过200'000和15'000.
由于大多数编译器实现C++的方式,您可能会看到后置条件被违反,但您实际观察到的是由于整数溢出而导致的未定义行为.
答案是他的前提条件检查不完整.即使它太严格了.
他未能检查产品是否可以代表而不是产生UB:
int area(int length, int width) { // calculate area of a rectangle assert(length >= 0 && width >= 0 && (!width || std::numeric_limits::max() / width >= length)); int a = length * width; assert(a >= 0); // Not strictly neccessary - the math is easy enough return a; }
我想到的是签名溢出.它是未定义的行为,但可能会产生负值.
尝试std::numeric_limits
和2
.