因此,当我们需要从头到尾遍历一个容器时,我们会写出如下的代码:
for (i = v->begin(); i != v->end(); i++)
假设 i
是容器 v
中的迭代器。
我的问题是,“什么保证 end 始终指向容器中最后一个元素的下一个元素?”STL 如何确保这种行为,并且是否存在这种情况不成立的可能性?
STL通过始终存储如下内容来确保这种行为:
最终 (双关语),重要的是 end()
是什么,只要它始终为end()
(并且显然不能与任何其他节点混淆)。
C++03第23.1/7
节规定:
begin()函数返回指向容器中第一个元素的迭代器。
end()函数返回指向容器末尾(即超出最后一个元素)的迭代器。
如果容器为空,则
begin() == end()
;
“end将始终指向容器中最后一个元素的下一个位置”,这意味着,如果你增加一个指向最后一个元素的迭代器,它将等于end()
的结果。实现可能不同。在Visual C++中,std::vector::end()
返回一个特定于实现的迭代器,其中包含零指针。
std::vector<T>::iterator
是一个随机访问迭代器。如果std::vector<T>::end()
返回(T*)0
,那么end()-begin()
将是非法的,但它需要返回std::vector::size()
。 - MSaltersend
返回一个实现特定的迭代器,它持有零指针。 - Kirill V. Lyadvinskyvector<>::end()
被定义为vector<>::begin()+vector<>::size()
,并且实际上存储在vector<>
对象中(GCC向量是通过三个指针:begin、end和end_of_capacity来实现的,其中如果向量为空,则begin==end
,始终begin+size()==end
,如果size()==capacity()
则end==end_of_capacity
。没有任何零指针可见。 - David Rodríguez - dribeas你在询问所有STL容器...没有特别提到vector,其中end() 可能被实现为你显然期望的那样。在std::map<>中,"end是最后一个使用的节点之后"只是一个逻辑概念,表达了你可以安全地从最后一个使用的节点递增,将其与抽象概念"end"区分/等同,并进行一些节点算术,在其中end被认为比最后一个使用的节点多一个。不要太字面理解。
正如之前的一些帖子所述,end()
是超过最后一个元素的。如果您需要通过迭代器访问最后一个元素,请使用iter = container.end() - 1;
。否则,在向量的情况下,variable = someVector.back();
,假设变量是someVector
包含的数据类型。
关于它指向末尾的保证,容器本身在内部处理。您只需像对待任何其他对象的黑盒子一样对待它,并相信它正确地执行即可。
每当容器被调整大小时,它将跟踪结束位置,并在您再次访问end()
之前更新。但是,根据容器的不同,如果您有一个迭代器并以某种方式更改它,则可能会使迭代器无效并中断迭代过程。
v->end()
显然效率较低...for (auto it = v.begin(), end = v.end(); it != end; ++it)
是规范形式,但在 C++0x 中也可以使用for (auto val : v)
或std::foreach
和 lambda 函数。 - Matthieu M.