我被要求在作业中复制std::string
,我在实施substr
功能时遇到问题。在一组测试中,老师给了我们一个length
等于-1
的测试。我的substr
宣言是:
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");
在我的-1
unsigned
系统18446744073709551615
中,9
是tam_
,例如假设开始为10
而10 < 9 + 18446744073709551615
为10 < 9 + (-1)
。
我期待:
length + 1
这样就抛出了异常,但实际上我得到了
new[]
哪个是假的,不会抛出异常。随着函数的继续,它会为大小size_t
分配一个char数组,由于18446744073709551615
将Workbooks.Open Filename:= "C:\file2"
视为应该Dim wk as Workbook, sh as worksheet, path as string
path = "C:\file2"
Set wk = Workbooks.Open(path)
Set sh = ActiveSheet
'etc...
,系统会拒绝该数组,ThisWorkbook
这会导致程序崩溃。
我想知道为什么我的预期结果不正确。
答案 0 :(得分:2)
难以检查溢出和下溢问题。通常,您需要在进行算术之前进行检查,而不是之后进行检查。
首先,让我们清楚发生了什么。
// 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。