size_t负值的算术

size_t arithmetic with negative value

本文关键字:size      更新时间:2023-10-16

我被要求在作业中复制std::string,我在实现substr函数时遇到问题。在老师给我们的一组测试中,有一个测试的length等于-1substr的矿山申报是:

Cadena substr(size_t start, size_t length) const;

我(认为)size_t会阻止传递负值。问题是在定义中我检查size() < start + length(假设tam_size()相同):

if (tam_ <  start + length)
throw std::out_of_range("Error");

在我的系统中,-1unsigned18446744073709551615,因此,例如假设 start 是9tam_10

我期待:

10 <  9 + 18446744073709551615

所以抛出异常,但实际上我得到

10 < 9 + (-1)

这是假的,不会抛出异常。随着函数的继续,它会为大小分配一个 char 数组length + 1,系统拒绝了该数组,因为new[]size_t视为应有的18446744073709551615,它是如此之大以至于导致程序崩溃。

我想知道为什么我的预期结果不正确。

溢出和下溢问题很难检查。 一般来说,您需要在进行算术之前进行检查,而不是之后。

首先,让我们弄清楚发生了什么。

// The call
foo.substr(9, -1);

-1是一个int,但函数需要std::size_t所以-1被转换,你得到真正的大数(RBN)。

然后,测试:

size() < start + length

这些是无符号类型,因此如果算术(即加法)超过可以表示的范围的上限或下限,则该值将环绕。 (对于有符号类型,行为将是未定义的。

在这里,length是RBN。 当您添加start和 RBN 时,添加将换行为一个小数字。 您错过了溢出检测。

要修复它,您需要检查两件事:(1)start是否在边界内,(2)start后字符串的其余部分是否比length长。

if (start > size() || size() - start < length)
throw std::::out_of_range("Error");

步骤 (1) 是关键,因为它保证步骤 (2) 中的减法不会低于 0。