它是否定义为为C++标准算法提供反转范围

Is it defined to provide an inverted range to C++ standard algorithms?

本文关键字:范围 标准 是否 定义 C++ 算法      更新时间:2023-10-16

考虑标准算法,比如说,std::for_each.

template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);

据我所知,实际上对两个InputIterator论点的相对状态没有要求。

这是否意味着以下内容在技术上是有效的?还是未定义?我能现实地期望它做什么

std::vector<int> v{0,1,2,3,4};
std::for_each(
   v.begin()+3,  // range [3,0)
   v.begin(),
   [](int){}
);

乔迪告诉我:

错误:函数需要有效的迭代器范围 [__first、__last(。[+ 13 条废弃线路]

但我无法判断此调试诊断的合规性。


当试图学究地确定以下行为的定义有多明确时,我想出了这个问题:

std::vector<int> v; // <-- empty
std::for_each(      // <-- total no-op? stated or just left to implication?
   v.begin(),
   v.end(),
   [](int){}
);

该标准明确要求last迭代器可从first迭代器访问。这意味着通过增加first应该能够最终达到last

24.1 迭代器要求

6 迭代器j称为可从迭代器访问 i当且仅当 表达式的应用序列有限++i 使i == j.如果可以从i访问j,则它们引用相同的 容器。

7 大多数库的算法模板都可以运行 在数据结构上具有使用范围的接口。范围是一对 指定计算开始和结束的迭代器。 范围[i, i)是空范围;通常,[i, j)指的范围 数据结构中的元素,从 i,但不包括j指出的那个。范围[i, j)为 当且仅当可从i访问j时有效。的结果 将库中的函数应用于无效范围是 定义。

结果是未定义。


C++03 标准:25.1.1 对于每个
C++11 标准:25.2.4 对于每个国家:

template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);

1 效果:将 f 应用于取消引用范围 [first, last( 中每个迭代器的结果,从 从第一个到最后一个 - 1

而另一部分将有效范围[first,last)定义为:

C++03 标准:24.1 迭代器要求
C++11 标准:24.2.1 迭代器要求

第7段

大多数对数据结构进行操作的库算法模板都具有使用范围的接口。范围是一对迭代器,用于指定计算的开始和结束。 范围 [i, i( 是空范围;通常,范围 [i, j( 是指数据结构中的元素,从 i 指向的元素开始,一直到 j 指向的元素,但不包括 j 指向的元素。范围 [i, j( 有效,当且仅当 j 可从 i 访问时。 将库中的函数应用于无效范围的结果是未定义的。


记得在某处读过这篇文章,只是浏览了一下:

C++ 标准库 - 教程和参考 - 尼古拉·乔斯蒂尔斯

这在以下位置有提及:

5.4.1 范围
调用方必须确保第一个和第二个参数定义有效范围。如果可以通过遍历元素从一开始就到达范围的末尾,则会出现这种情况。这意味着,程序员有责任确保两个迭代器属于同一个容器,并且开头不落后于结尾。如果不是这种情况,则行为未定义,可能会导致无限循环或禁止的内存访问

这是否意味着以下内容在技术上是有效的?还是 定义?我能现实地期望它做什么?

不,不是。当for_each增加迭代器时,您的代码将表现出未定义的行为,并且该迭代器将指向end并且没有什么可以取消引用的(好吧,此时获得未定义的行为就足够了,所以谈论过去的结束是没有意义的(!

这由标准"迭代器要求"的第 24.1 节解释:

迭代器j称为可从迭代器i访问当且仅当表达式++i的有限应用序列使i == j。如果j可以从i访问,则它们引用同一容器。

范围 [i, j) 有效当且仅当可从 i 访问j。将库中的函数应用于无效范围的结果是未定义的。

所以v.begin() + 3可以从v.begin()到达,但不能相反。因此,[v.begin()+3, v.begin())不是有效范围,并且您对for_each的调用未定义。

该标准定义了采用范围的函数的复杂性约束。在for_each的特定情况下(C++标准中的 25.2.4(:

复杂性:精确f last - first次应用

因此,在您的示例中,它实际上是一个无操作。