考虑标准算法,例如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){}
);
geordi告诉我:
错误:函数需要有效的迭代器范围[__ 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){}
);
答案 0 :(得分:21)
标准明确要求last
迭代器可以从first
迭代器到达。这意味着通过递增first
,最终应该能够点击last
。
24.1迭代器要求
...
6 迭代器
j
从迭代器i
调用,当且仅当 表达式++i
的应用程序有限 制作i == j
。如果可以从j
访问i
,则表示相同 容器。7 大多数库的算法模板都在运行 数据结构上有使用范围的接口。范围是一对 指定计算开始和结束的迭代器。 范围
[i, i)
是一个空范围;通常,范围[i, j)
指的是 数据结构中的元素以指向的元素开头i
,但不包括j
指向的那个。范围[i, j)
是 当且仅当j
可以从i
访问时有效。结果 将库中的函数应用于无效范围是 未定义。
答案 1 :(得分:6)
结果为未定义。
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段:
在数据结构上运行的大多数库的算法模板都有使用range的接口。范围是一对指定计算开始和结束的迭代器。范围[i,i]是空范围;通常,范围[i,j]是指数据结构中的元素,从i指向的那个开始,直到但不包括j指向的元素。 当且仅当j可从i到达时,范围[i,j]才有效。将库中的函数应用于无效范围的结果未定义。
记得在某个地方读过这篇文章,只是浏览过:
C ++标准库 - 教程和参考 - 作者Nicolai Josutils
这在以下内容中提到:
5.4.1范围
调用者必须确保第一个和第二个参数定义有效范围。如果通过遍历元素从一开始就可以到达,那么就是这种情况。 这意味着,程序员必须确保两个迭代器都属于同一个容器,并且开头不在末尾。如果不是这种情况,则行为未定义,可能导致无限循环或禁止内存访问。
答案 2 :(得分:2)
这是否意味着以下技术上有效?或者是它 未定义?我可以实际期望它做什么?
不,不是。当for_each
递增迭代器并且迭代器指向end
时,您的代码将显示未定义的行为,并且没有任何内容可以取消引用(嗯,此时它足以获得未定义的行为,所以有没有必要谈论过去的结局)!
答案 3 :(得分:2)
标准的第24.1节“迭代器要求”对此进行了解释:
迭代器
j
从迭代器i
被称为可到达当且仅当表达式++i
的应用程序的有限序列{ {1}}。如果i == j
可以从j
访问,则它们会引用同一个容器。...
当且仅当i
可以从[i, j)
访问时,范围
j
才有效。将函数库中的函数应用于无效范围的结果是未定义的。
所以i
可以从v.begin() + 3
到达,但不能相反。因此v.begin()
不是有效范围,您对[v.begin()+3, v.begin())
的调用未定义。
答案 4 :(得分:1)
该标准定义了采用范围的函数的复杂性约束。在for_each
的特定情况下(C ++标准中为25.2.4):
复杂性:恰好
f
次last - first
次
所以在你的例子中它实际上是一个无操作。