std :: next with n> std :: distance(it,c.end())

时间:2016-07-11 11:14:54

标签: c++ c++11 stl

我不想使用std::distance,因为它会计算从迭代器到结尾的整个距离。但我需要确保从迭代器到结尾有N个或更多元素。所以我使用下一个代码:

if (std::next(it, n) != c.end()) // c is a std::multimap
{
    /// my logic
}

一切都很棒并且与我的编译器(g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9))合作但我有疑问。在文档(cpprefenece.com&& cplusplus.com)中,在n > std::distance(it , c.end())或任何其他特殊情况下,我找不到有关案例的任何信息。所以。我的代码安全吗?或者我应该写自己的nextIfPossible

3 个答案:

答案 0 :(得分:4)

根据标准§24.4.4/ p3& p6迭代器操作[iterator.operations](强调我的):

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

2 要求:n仅对双向和随机为负   访问迭代器。

     

3 效果:增量(或减去负数n)   迭代器引用i by n。

template <class InputIterator>
constexpr InputIterator next(InputIterator x,
typename std::iterator_traits<InputIterator>::difference_type n = 1);
     

6 效果:相当于:advance(x, n); return x;

因此,没有绑定检查,因此如果输入n大于std::distance(it , c.end()),则可能导致未定义的行为。

答案 1 :(得分:3)

如果next(it, n)小于distance(it, c.end()),则

n是未定义的行为。

  

[C ++ 14:5.7 / 5]如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。

有关详细信息,请参阅此处:Are non dereferenced iterators past the "one past-the-end" iterator of an array undefined behavior?

必须编写nextIfPossible或您的代码未定义。也就是说,因为我猜这是一个随机访问迭代器,所以在必须执行边界检查的情况下,你会发现使用索引比使用迭代器更快地进行基准测试:https://stackoverflow.com/a/37299761/2642059

因此我建议不要使用迭代器或nextIfPossible,而只是使用索引并根据大小进行检查。

答案 2 :(得分:0)

RB_Tree::iteratorlibstd++递增运算符的实现确保它不会将迭代器返回到未定义的内存位置:

static _Rb_tree_node_base*
  local_Rb_tree_increment(_Rb_tree_node_base* __x) throw ()
  {
    if (__x->_M_right != 0)
      {
        __x = __x->_M_right;
        while (__x->_M_left != 0)
          __x = __x->_M_left;
      }
    else
      {
        _Rb_tree_node_base* __y = __x->_M_parent;
        while (__x == __y->_M_right)
          {
            __x = __y;
            __y = __y->_M_parent;
          }
        if (__x->_M_right != __y)
          __x = __y;
      }
    return __x;
  }

std::vector

的情况并非如此
#include <iostream>
#include <vector>
#include <iterator>

int main() {
  std::vector<int> vec = {1,2};
  auto it = vec.begin();
  it = std::next(it, 5);
  if (it != vec.end()) {
    std::cout << "Not end..go on" << std::endl;
  }
  return 0;
}

这将继续打印消息..

因此,由于容器之间的行为不相同,因此您不应依赖std::next来确定基于map的容器的当前正确行为。