STL源码剖析(三)---迭代器

迭代器是STL中提供的对容器中对象的访问方法。它就像指针,可以用*运算符获取数据,可以使用++,--对迭代器进行操作。

迭代器的范围可以由begin()和end()这两个函数获得,begin()返回指向容器中的第一个元素的迭代器,end()返回指向容器的最后一个元素的下一个位置的迭代器。

迭代器是如何访问到容器中的数据呢?

在list中,定义了一个名字是__list__iterator的结构体,里面实现了一系列类似于指针操作的重载函数。

template<class T, class Ref, class Ptr>
struct __list_iterator {
  typedef __list_iterator<T, T&, T*>             iterator;
  typedef __list_iterator<T, const T&, const T*> const_iterator;
  typedef __list_iterator<T, Ref, Ptr>           self;

       ...

  link_type node;     //一个链表结点

  __list_iterator(link_type x) : node(x) {}
  __list_iterator() {}
  __list_iterator(const iterator& x) : node(x.node) {}

  bool operator==(const self& x) const { return node == x.node; }
  bool operator!=(const self& x) const { return node != x.node; }
  reference operator*() const { return (*node).data; }

       ...
  self& operator++() { 
    node = (link_type)((*node).next);
    return *this;
  }
  self operator++(int) { 
    self tmp = *this;
    ++*this;
    return tmp;
  }
  self& operator--() { 
    node = (link_type)((*node).prev);
    return *this;
  }
  self operator--(int) { 
    self tmp = *this;
    --*this;
    return tmp;
  }
};

再看list类中:

template <class T, class Alloc = alloc>
class list {
protected:
     ...
public:
  typedef __list_iterator<T, T&, T*>             iterator;
  typedef __list_iterator<T, const T&, const T*> const_iterator;

    ...

protected:
  link_type node;      //这是链表的头结点

public:
  list() { empty_initialize(); }

  iterator begin() { return (link_type)((*node).next); }
  const_iterator begin() const { return (link_type)((*node).next); }
  iterator end() { return node; }
  const_iterator end() const { return node; }
  
}

 
可以看到begin()返回的是头结点的下一个结点,而end()返回的是头结点,表示最后一个元素的下一个元素,这也是STL中的list要带头结点的重要原因。 

有了头结点,__list__iterator中又实现了++,-- ,*的重载,这样就可以很方便地像指针一样遍历链表啦。

其它容器中迭代器的结构类似。但vector中却不是这样的。

在vector中:

template <class T, class Alloc = alloc>
class vector {
public:
  typedef T value_type;
  typedef value_type* pointer;
  typedef const value_type* const_pointer;
  typedef value_type* iterator;
  typedef const value_type* const_iterator;
 
protected:
  iterator start;
  iterator finish;
  iterator end_of_storage;
 
     ...
public:
  iterator begin() { return start; }
  const_iterator begin() const { return start; }
  iterator end() { return finish; }
  const_iterator end() const { return finish; }
            ...
 }


可以看到vector的iterator其实就是某种数据类型的指针,因为vector的底层就是数组,start指向一段从内存中开辟的连续空间,指针本身就可以遍历它,就不需要再去实现一些函数的重载啦。
 

------------------------------------------------------------------------------------------------------

迭代器的使用:

#include<iostream>
#include<stdlib.h>
#include<vector>
using namespace std;

int main()
{
	vector<int> vt;
	vt.push_back(1);
	vt.push_back(2);
	vt.push_back(3);
	vt.push_back(4);

	vector<int>::iterator it = vt.begin();
	while(it != vt.end())
	{
		cout<<*it<<" ";
		++it;
	}

	system("pause");
	return 0;
}

使用迭代器要注意迭代器失效的问题,举一个例子:

<pre name="code" class="cpp">#include<iostream>
#include<stdlib.h>
#include<list>
using namespace std;

int main()
{
	list<int>  ls;
	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);

	list<int>::iterator it = ls.begin();
	while(it != ls.end())
	{
		if(*it % 2 ==0)
			 ls.erase(it);
			
		++it;
	}
	system("pause");
	return 0;
}


 

删除list中是2的倍数的结点,但是程序一运行就会崩溃。

问题出在++it,把2删除了之后,it指向的空间已经被释放了,再++it,程序当然会崩溃。

解决方案:

1)

#include<iostream>
#include<stdlib.h>
#include<list>
using namespace std;

int main()
{
	list<int>  ls;
	ls.push_back(1);
	ls.push_back(2);
	ls.push_back(3);
	ls.push_back(4);

	list<int>::iterator it = ls.begin();
	while(it != ls.end())
	{
		list<int>::iterator tmp = it;
		++it;

		if(*tmp % 2 ==0)
			 ls.erase(tmp);
	}
	system("pause");
	return 0;
}
2)

list<int>::iterator it = ls.begin();
	while(it != ls.end())
	{
		if(*it % 2 ==0)
			 it = ls.erase(it);
		else	
			++it;
	}
因为erase会返回指向下一个结点的迭代器。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值