我不想使用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
?
答案 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::iterator
中libstd++
递增运算符的实现确保它不会将迭代器返回到未定义的内存位置:
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
的容器的当前正确行为。