使用cpp STL都不会不知道迭代器,那迭代器到底是什么呢?
在http://www.cplusplus.com 中对迭代器的定义为:An iterator is any object that, pointing to some element in a range of elements (such as an array or a container), has the ability to iterate through the elements of that range using a set of operators (with at least the increment (++<) operators). 即迭代器就是指向一系列元素中的某一个元素,它能通过一系列操作迭代访问其中的元素。另外,需要注意的是cpp中的迭代器虽然绝大多数的本质就是指针,但并不是所有的迭代器都是指针,也有可能是其他形式,并且不保证迭代器具有指针的所有功能,比如input 和 output iterator就是一种单向受限的迭代器,执行--操作没有任何意义。cpp中,根据迭代器实现的不同功能,大体可以把迭代器分为5大类,具体各个类支持什么操作,查看迭代器。
现在重点看看cpp中vector中的迭代器,vector的迭代器是一个random access iterator,即随机访问迭代器,具有指针的所有操作。现在看看sgi源码中关于迭代器的实现(stl 3.3)。首先看看iterator的类型定义:
typedef _Tp value_type; typedef value_type* iterator; typedef const value_type* const_iterator;
其中_Tp是范型参数类型,比如声明vector<int>,则_Tp为int,根据类型定义,很显然vector中的iterator 本质就是一个指针,vector<int>::iterator其实就是int *类型。
看vector的方法begin() 和 end()
iterator begin() { return _M_start; } const_iterator begin() const { return _M_start; } iterator end() { return _M_finish; } const_iterator end() const { return _M_finish; }
可以看到,begin和end方法直接返回_M_start 和_M_finish,这两个私有属性就是iterator类型,即指针,前者指示。由于vector实现本质就是一个动态数组,_M_start则指示数组第一个元素,而_M_finish则指示数组最后一个元素的下一个单元,注意是下一个元素,因此_M_finish指向的单元不能访问,只是一个哨兵。vector更新时(比如初始化、push_back,pop_back等)都需要不断的维护这两个指针(实际上是3个,还有个_M_end_of_storage用于指示当前已分配内存的最后一个单元),而vector中的很多方法也是需要利用这两个指针的,比如以下方法:
size_type size() const { return size_type(end() - begin()); } size_type capacity() const { return size_type(_M_end_of_storage - begin()); } bool empty() const { return begin() == end(); }
我们也可以发现,既然是迭代器指针,那就存在不安全性,有可能越界访问,更有可能所引用的迭代器是失效的,即在返回迭代器后,又对容器进行了修改,而这些都需要用户自己注意,库并没有对这些进行检查。java在这方面会比较好点。
根据以上模拟一个简单的vector(只有push_back 和 pop_back方法),对vector原理会更清楚些:
template <class T> class vector { public: typedef T value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef value_type* iterator; typedef value_type* pointer; typedef value_type& reference; iterator begin() { return M_start; } iterator end() { return M_end; } size_type size() { return size_type(end() - begin()); } size_type capacity() { return size_type(end_of_storage-begin()); } bool empty() { return begin() == end(); } reference operator[](size_type n) { return *(begin() + n); } vector() { M_start = M_end = end_of_storage = 0; } vector(size_type n) { M_start = new T[n](); M_end = M_start; end_of_storage = M_start + n; } ~vector() { destroy(begin(), end()); delete[] M_start; } void push_back(value_type i) { if (M_end < end_of_storage) { *M_end++ = i; return; } size_type old_capacity = capacity(); size_type new_capacity = old_capacity == 0 ? 16 : old_capacity << 1; iterator new_M_start = new T[new_capacity](); iterator new_M_end = new_M_start; iterator iter; for(iter = begin(); iter != end(); ++iter) { *new_M_end++ = *iter; } delete [] M_start; M_start = new_M_start; M_end = new_M_end; end_of_storage = M_start + new_capacity; *M_end++ = i; } void pop_back() { if (begin() == end()) return; --M_end; destroy(M_end); } private: iterator M_start; iterator M_end; iterator end_of_storage; void destroy(pointer p) { p->~T(); } void destroy(iterator start, iterator end) { iterator iter; for (iter = start; iter != end; iter++) { iter->~T(); } } };
分配内存时按照原有内存2倍关系分配,即如果当前分配了8B, 则下次分配16B,这样能够减少频繁内存分配,提高性能。可以不难看出,在访问元素时,无论是用迭代器还是[ ]运算符,都没有进行越界检测。
看看java的迭代器,主要是看看与cpp中vector迭代器的不同。
java支持迭代,必须实现Iterator接口,该接口定义为:
public interface Iterator<E> { boolean hasNext(); E next(); void remove(); }
该接口只有三个方法,实现该接口必须实现这三个方法。 下面看看ArrayList如何实现该接口,从而了解其原理。 ArrayList 的iterator方法:
public Iterator<E> iterator() { return Itr(); }
看来只好再看看ArrayList的基类 AbstractList,可以发现其实 Itr是AbstractList的私有内部类,其实现为:
private class Itr implements Iterator<E> { /** * Index of element to be returned by subsequent call to next. */ int cursor = 0; /** * Index of element returned by most recent call to next or * previous. Reset to -1 if this element is deleted by a call * to remove. */ int lastRet = -1; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ int expectedModCount = modCount; public boolean hasNext() { return cursor != size(); } public E next() { /* 检查列表是否被修改过 */ checkForComodification(); try { int i = cursor; E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { /* 调用外部类的remove方法 */ AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
我们发现java中的迭代器是通过实现Iterator接口实现的,为了方便访问内部属性,一般声明为一个实现Iterator的内部类,因为内部类能够访问外部类的所有属性和方法。而实现方法也很简单,就是用一个cursor游标标识当前位置。我们也发现,java中迭代器比cpp中迭代器更安全,首先能够保证不会越界访问,另外还会检查是否原来的实例被修改过,即保证迭代器是有效的。
2021年9月16日 18:44
Your blog has piqued a lot of real interest. I can see why since you have done such a good job of making it interesting. I appreciate your efforts very much. 123movie
2021年11月05日 03:12
What a fantabulous post this has been. Never seen this kind of useful post. I am grateful to you and expect more number of posts like these. Thank you very much. 오피아트 주소
2023年1月31日 21:37
"After study a few of the blog posts on your website now, and I truly like your way of blogging. I bookmarked it to my bookmark website list and will be checking back soon. Pls check out my web site as well and let me know what you think.
"
2023年2月05日 04:36
"Very good written article. Keep writing – I will visit again to see more of your posts.
"
2023年3月22日 04:39
"Really a great addiction. I have read this great art.
"
2023年4月19日 08:29
I am very happy to discover your post as it will become on top in my collection of favorite websites to visit.
2023年6月05日 04:58
"
Nice to be visiting your blog again, it has been months for me. Well this article that i've been waited for so long. I need this article to complete my assignment in the college, and it has same topic with your article. Thanks"
2023年8月20日 03:59
Hey, I am so thrilled I found your blog, I am here now and could like to thank you for a tremendous post and all-round interesting website. Please keep up the great work. I cannot be without visiting your blog again and again.
2023年9月15日 05:51
I definitely enjoying every little bit of it. It is a great website and nice share. I want to thank you. Good job! You guys do a great blog, and have some great contents. Keep up the good work.
2023年9月26日 05:26
I was exceptionally satisfied to find this site.I needed to thank you for this extraordinary read!! I most certainly partaking in every single piece of it and I have you bookmarked to look at new stuff you post.
2023年11月05日 05:00
I’m happy to find so many useful info here in the post, thanks for sharing. I love the variety of content available on your website. I’ll bookmark your blog and take the feeds also!
2024年6月06日 08:49
Wow! Such an amazing and helpful post this is. I really really love it. It's so good and so awesome. I am just amazed. I hope that you continue to do your work like this in the future also.
2024年9月06日 21:12
Excellent layout and content combination. Your website is deserving of all the compliments it has been receiving. I'll be back soon with more excellent material. 丹麥公民的印度簽證
2024年10月17日 14:08
Although I don't read articles online very frequently, I'm glad I did today. Your views are well stated, and it is quite well written. I really ask that you never stop writing. индийска виза за притежателите на паспорти на Индонезия
2024年12月03日 19:35
Good post overall. I recently came onto your blog and really loved reading the content. I'm searching for fresh content to obtain even more valuable information. Regards for the helpful information. cambodia visa for belarusian citizens
2025年1月05日 21:42
The tips for using a Bitcoin mixer safely reflect a commitment to responsible use and user education in the cryptocurrency community. situs slot
2025年1月08日 07:15
I appreciate your great blog. Where else might I get information conveyed in such a flawless manner? I have a project that I am currently working on, and I have been watching for such info. morate posjetiti plaže u Turskoj