为什么标准不允许 std::for_each 对无效的随机访问迭代器范围有明确定义的行为?

Why doesn't the standard allow std::for_each to have well-defined behavior on invalid random access iterator ranges?

本文关键字:范围 迭代器 定义 访问 随机 for 标准 std each 为什么 无效      更新时间:2023-10-16

在这个问题中,有人解释说,当给定一个无效的迭代器范围[first,last)时,std::for_each具有未定义的行为(即,当last不能通过先递增来访问时)。

这可能是因为一般循环for(auto it = first; it != last; ++it)将永远在无效范围上运行。但对于随机访问迭代器来说,这似乎是一个不必要的限制,因为随机访问迭代器有一个比较运算符,可以将显式循环写成for(auto it = first; it < last; ++it)。这将把一个无效范围的循环变成no-op。

所以我的问题是:为什么标准不允许std::for_each在无效的随机访问迭代器范围上有定义良好的行为?它将简化一些只对多元素容器(例如排序)有意义的算法。使用运算符<()而不是运算符=()?

这将把一个无效范围的循环变成no-op。

事实并非如此。

无效范围的一个示例是当firstlast引用不同的容器时。比较这样的迭代器至少在某些情况下会导致未定义的行为。

这将把一个无效范围的循环变成no-op。

您似乎在说,对于不属于同一范围的两个随机访问迭代器,operator<应该始终返回false。这是你指定的循环成为no-op的唯一方法。

标准规定这一点是没有意义的。请记住指针是随机访问迭代器。想想指针操作的实现负担,以及给读者带来的普遍困惑,如果定义以下代码打印"两个":

int a[5];
int b[5]; // neither [a,b) nor [b,a) is a valid range
if ((a < b) || (b < a)) {
    std::cout << "onen";
} else {
    std::cout << "twon";
}

相反,它是未定义的,这样人们一开始就不会写它。

因为这是一般策略。所有使用<都允许类似:

std::for_each( v.begin() + 20, v.begin() + 10, op );

即使使用<,也会传递无效的迭代器或来自不同容器,是未定义的行为。