std ::推进超出容器结束时的行为

时间:2011-05-06 19:41:26

标签: c++ stl

当你说:

时,std :: advance的行为是什么?
std::vector<int> foo(10,10);
auto i = foo.begin();
std::advance(i, 20);

的价值是多少?它是 foo.end()吗?

5 个答案:

答案 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。

IdeOne Results

答案 3 :(得分:1)

来自std::advance的SGI页面:

  

i和i + n之间的每个迭代器   (包括在内)是非奇异的。

因此我不是foo.end(),并且取消引用会导致未定义的行为。

注意:

  1. 有关引用迭代器时(非)单数意味着什么的更多详细信息,请参阅this question
  2. 我知道SGI页面不是事实上的标准,但几乎所有STL实现都遵循这些准则。

答案 4 :(得分:1)

这可能是未定义的行为。标准所说的唯一内容是:

由于只有随机访问迭代器提供+和 - 运算符,因此库提供了两个函数模板advance和distance。这些函数模板使用+和 - 用于随机访问迭代器(因此,它们是恒定的时间);对于输入,转发和双向迭代器,它们使用++来提供线性时间实现。

template <class InputIterator, class Distance> 
void advance(InputIterator& i, Distance n);

要求:对于双向和随机访问迭代器,n应为负数。效果:增量(或负n的减量)迭代器引用i由n。