当你说:
时,std :: advance的行为是什么?std::vector<int> foo(10,10);
auto i = foo.begin();
std::advance(i, 20);
我的价值是多少?它是 foo.end()吗?
答案 0 :(得分:31)
标准根据它所使用的迭代器类型定义std::advance()
(24.3.4“迭代器操作”):
这些函数模板使用+和 - 用于随机访问迭代器(因此,它们是恒定的时间);对于输入,转发和双向迭代器,它们使用++来提供线性时间实现。
标准中还列出了对各种迭代器类型的这些操作的要求(表72,74,75和76):
对于输入或转发迭代器
++r precondition: r is dereferenceable
用于双向迭代器:
--r precondition: there exists s such that r == ++s
对于随机访问迭代器,+
,+=
,-
和-=
操作是根据双向和&amp;转发迭代器前缀++
和--
操作,因此保持相同的前提条件。
因此,将迭代器推进到“过去 - 结束”值之外(可能由容器上的end()
函数返回)或者在迭代器的有效范围的第一个可解除引用的元素之前前进(可能会返回)由于begin()
或++
操作违反了--
或{{1}}操作的前提条件,因此{{1}}在容器上)是未定义的行为。
由于它是未定义的行为,你无法“期待”任何特别的东西。但是你可能会在某些时候崩溃(希望更快而不是更晚,所以你可以解决这个问题)。
答案 1 :(得分:7)
根据C ++标准§24.3.4std::advance(i, 20)
与for ( int n=0; n < 20; ++n ) ++i;
的积极n
具有相同的效果。从另一方面(第24.1.3节)如果i
是过去的,那么++i
操作是未定义的。因此std::advance(i, 20)
的结果未定义。
答案 2 :(得分:3)
您通过提升到第20位而通过foo
大小。绝对不是矢量的结束。它应该在解除引用,AFAIK上调用未定义的行为。
编辑1:
#include <algorithm>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> foo(10,10) ;
std::vector<int>::iterator iter = foo.begin() ;
std::advance(iter,20);
std::cout << *iter << "\n" ;
return 0;
}
输出 0
如果它是向量的最后一个元素,那么它应该在迭代器解除引用时给出10。所以,它是UB。
答案 3 :(得分:1)
来自std::advance的SGI页面:
i和i + n之间的每个迭代器 (包括在内)是非奇异的。
因此我不是foo.end(),并且取消引用会导致未定义的行为。
注意:
答案 4 :(得分:1)
这可能是未定义的行为。标准所说的唯一内容是:
由于只有随机访问迭代器提供+和 - 运算符,因此库提供了两个函数模板advance和distance。这些函数模板使用+和 - 用于随机访问迭代器(因此,它们是恒定的时间);对于输入,转发和双向迭代器,它们使用++来提供线性时间实现。
template <class InputIterator, class Distance>
void advance(InputIterator& i, Distance n);
要求:对于双向和随机访问迭代器,n应为负数。效果:增量(或负n的减量)迭代器引用i由n。