2

另一种看待 C++ 反向迭代器的方式中, Raymond Chen 写道:

... C++ 语言的一个怪癖:您可以有一个指针“在集合的末尾”,但不允许您在集合的“开始之前”有一个指针。

我知道这可能意味着“未定义的行为”,这几乎是一个对话终结者。但我很好奇如果忽略这条规则,在现实系统中可能发生的最坏情况是什么。分段错误?指针算术溢出?不必要的分页?

请记住,开始“之前”的指针(如“end”)也不应该被引用,问题似乎是指针只是试图指向它。

我能想象的唯一可能出现问题的情况是内存位置“0”有效的系统。但即便如此,如果是这样的话,会有更大的问题,(例如 nullptr 本身也会有问题,我猜想按照惯例,环绕可能仍然有效。)

我不是在质疑reverse_iterator使用非一的特殊代码的实现。我想到了这个问题,因为如果你有一个“跨步”迭代器的通用实现,那么负跨步需要一个特殊的逻辑,并且有成本(在代码和运行时)。

任意步幅,包括负步幅,自然会出现在多维数组中。我有一个多维数组库,原则上我总是允许负步幅,但现在我意识到,如果我完全允许它们并且我不想暴露未定义的行为,它们应该有一个特殊的代码(不同于正例) .

4

1 回答 1

2

但我很好奇如果忽略这条规则,在现实系统中可能发生的最坏情况是什么。分段错误?指针算术溢出?不必要的分页?

浪费空间。

为了能够形成“前一个”地址,您需要有可用空间。例如,如果你有一个 1k 的结构,它必须从内存开始至少 1k 开始。在内存有限的小型设备或具有分段内存的 x86 上,这可能会很棘手。

要形成一个“过去的”指针/迭代器,您只需要超出末尾的一个字节。因为它无论如何都不能被取消引用,所以不需要为整个对象留出空间,只需要形成地址的可能性。


从评论:

在定义规则时,我们拥有带有专用地址寄存器的真实 CPU,这些寄存器在寄存器加载时根据段大小验证地址。这确保了一个-1地址会陷阱......

https://en.wikipedia.org/wiki/Motorola_68000#Architecture

这排除了“一个之前”环绕到段末尾的情况。因为如果段很小,则结果端可能不存在。

于 2021-12-12T09:42:02.903 回答