stl源码剖析01——迭代器

1. 迭代器概述

  • 不论是泛型思想或是STL的实际运用,迭代器都扮演着重要的角色
  • STL的中心思想在于:将数据容器和算法分开,彼此独立设计,最后再以一种胶着剂将它们撮合在一起

2. 迭代器是独立于容器和算法而存在的

下面介绍一个容器、算法、迭代器在一起使用的案例

演示案例

  • 下面是find()算法的源码(摘录于<stl_algo.h>)
template<class InputIterator,class T>

InputIterator find(InputIterator first, InputIterator last,

const T& value)

{

    while (first != last&&*first != value)

        ++first;

    return first;

}
  • 在程序中定义了不同的迭代器,find()能够根据不同的容器进行查找操作:
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
#include <deque>

using namespace std;

int main()
{
	const int arraySize = 7;
	int ia[arraySize] = { 0,1,2,3,4,5,6 };

	vector<int> ivect(ia, ia + arraySize);
	list<int> ilist(ia, ia + arraySize);
	deque<int> ideque(ia, ia + arraySize);

	vector<int>::iterator iter1 = find(ivect.begin(), ivect.end(), 4);
	if (iter1 == ivect.end())
		std::cout << "4 not found" << std::endl;
	else
		std::cout << "4 found" << std::endl;

	list<int>::iterator iter2 = find(ilist.begin(), ilist.end(), 6);
	if (iter2 == ilist.end())
		std::cout << "6 not found" << std::endl;
	else
		std::cout << "6 found" << std::endl;

	deque<int>::iterator iter3 = find(ideque.begin(), ideque.end(), 8);
	if (iter3 == ideque.end())
		std::cout << "8 not found" << std::endl;
	else
		std::cout << "8 found" << std::endl;

	system("pause");
	return 0;
}

  • 可以看出,迭代器是独立于容器与算法的

三、迭代器是一种smart pointer(智能指针)

  • 迭代器是一种行为类似指针的对象,而指针的各种行为中最常见的便是“内容提领”与“成员访问”。因此迭代器最重要的工作就是对operator*和operator->进行重载

以auto_ptr为例

  • auto_ptr现在已过时,取代物是unique_ptr。但是此处我们以auto_ptr来演示说明
  • auto_ptr是一个用来包装原生指针的对象
  • 下面是auto_ptr的简略化的源码:
template <class T>

class auto_ptr

{

public:

    explicit auto_ptr(T* p = 0) :pointee(p) {}

    template<class U>

    auto_ptr(auto_ptr<U>& rhs) : pointee(rhs.release()) {}

    ~auto_ptr() { delete pointee; }


    template<class U>

    auto_ptr<T>& operator=(auto_ptr<U>& rhs) {

        if (this != rhs)

            reset(rhs.release());

        return *this;

    }


    T& operator*()const { return *pointee; }
    
    T* operator->()const { return pointee; }

    T* get()const { return pointee; }

private:

    T* pointee;

};
  • 下面是auto_ptr的使用:
int main()

{

    auto_ptr<string> ps(new string("dongshao"));


    std::cout << *ps << std::endl; //输出dongshao

    std::cout << ps->size() << std::endl;//输出5


    return 0;

}

 

设计自己的迭代器

  • 我们有一个自己的链表容器类List,其中ListItem是链表的节点类
template<typename T>

class List

{

public:

    void insert_front(T value);

    void insert_end(T value);

    void display(std::ostream &os = std::cout)const;


    ListItem* end()const { return _end; }

    ListItem* front()const { return _front; }

private:

    ListItem<T>* _end;

    ListItem<T>* _front;

    long _size;

};


template<typename T>

class ListItem

{

public:

    T value()const { reutrn value; }

    ListItem* next()const { return return _next; }
    
private:

    T _value;

    ListItem* _next;

};
  • 如何将我们的List应用于我们的find()函数呢?我们需要为它设计一个行为类似指针的外衣,也就是一个迭代器:
    • 我们提领(*)这个迭代器时,返回的是节点对象ListItem
    • 当我们递增该迭代器时,指向于下一个ListItem对象
  • 但是为了让迭代器适用于任何类型的节点,而不仅限于ListItem,我们将迭代器设计为一个类模板
template<class Item>

struct ListIter

{

    Item* ptr;


    ListIter(Item* p = 0) :ptr(p) {}


    Item& operator*()const { return *ptr; }

    Item* operator->()const { return ptr; }


    ListIter& operator++() {

    ptr = ptr->next();

    return *this;

}

ListIter& operator++(int) {

    ListIter tmp = *this;

    ++*this;

    return tmp;
    
}


bool operator==(const ListIter& i)const { return ptr == i.ptr; }

bool operator!=(const ListIter& i)const { return ptr != i.ptr; }

};
  • 由于find()算法内以*iter!=value来检查元素值是否吻合,而本例中的value的类型是int,iter的类型是ListItem<int>,两者不能直接进行比较,因此还需要设计一个全局的operator!=重载函数,并以int和ListItem<int>为参数:
template<typename T>

bool operator!=(const ListItem<T>& item, T n)

{

    return (item->value() != n);

}
  • 现在我们可以使用我们自己的容器与迭代器了:
int main()

{

    List<int> myList;


    for (int i = 0; i < 5; ++i) {

        myList.insert_front(i);

        myList.insert_end(i + 2);

    }


    ListIter<ListItem<int> > begin(myList.front());

    ListIter<ListItem<int> > end;

    ListIter<ListItem<int> > iter;


    iter = find(begin, end, 3);

    if (iter == end)

        std::cout << "3 not found" << std::endl;

    else

        std::cout << "3 found" << std::endl;


    return 0;

}
  • 从上面的实现可以看出,为了完成一个针对List而设计的迭代器,我们暴露了太多List实现细节:
    • 在main函数中,为了制作begin()和end()两个迭代器,我们暴露了ListItem
    • 在ListIter类中为了达成operator++的目的,我们暴露了ListItem的操作函数next()
  • 如果不是为了迭代器的设计,ListItem原本应该完全隐藏。所以,为了避免暴露我们设计容器的细节,我们应该将迭代器的所有实现细节也封装其容器类中,这也正是每一个STL容器都提供了一份专属于自己的迭代器的缘故
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值