PoEdu培训 STL班 第八课 STL源码解析之迭代器(一)
文章类别: 培训笔记 0 评论

PoEdu培训 STL班 第八课 STL源码解析之迭代器(一)

文章类别: 培训笔记 0 评论

STL迭代器(一) 初识迭代器

迭代器

我们在使用STL的时候, 我们会通过迭代器来操作容器.
它相当于一个桥梁, 是一个标准的接口.
它类似一个指针, 实现了指针的部分操作.

迭代器的种类:

每种迭代器支持的功能不同.

本质剖析

SGI中vector的迭代器

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> demo;
    demo.push_back(1);
    demo.push_back(2);
    demo.push_back(3);
    demo.push_back(4);
    demo.push_back(5);

    std::vector<int>::iterator it;
    it = demo.begin();
    for (; it != demo.end(); ++it)
    {
        std::cout << *it << std::endl;
    }
    return 0;
}

根据以上的小例子, 我们拿出SGI的代码, 来看一下这个迭代器.

找到iterator的定义, 如下图所示:
Alt 01

    可以看到, iterator是 value_type* 类型.
    而value_type是我们的 _Tp

由此可见, SGI中的vector里的迭代器就是一个指针.

SGI中list的迭代器

std::list<int>::iterator it;

同样, 我们首先找到 iterator的定义.
Alt 02

    可以看到, list的iterator 和 const_iterator 都是一个模板类 _List_iterator
    我们查看一下 _List_iterator 这个模板类.

Alt 03

    可以看到, 该类重载了 operator* operator-> operator++ operator--操作符.
    这是迭代器常用的操作.
    不知道大家有没有一个疑问, 为什么没有 operator[] 呢? 这个问题我们先留下, 留到下节课来解答.
    我们又注意到, operator++ 和 operator-- 调用了方法, 而方法在本类中没有.
    然后, 我们发现这个模板类继承自 _List_iterator_base 这个类.
    注意, 继承的这个类不是模板类.
    我们继续跟入 _List_iterator_base 这个类.

Alt 04

    可以看到, 这个类实现了++和--的方法.
    本质上, 它们是对链表的 next 和 prev 进行访问.

看到这里, 我们知道了, list的迭代器是一个类, 实现了一部分的指针操作.

Visual Studio 中的vector的迭代器

#include <vector>

int main()
{
    std::vector<int>::iterator it;

    return 0;
}

同样的, 我们首先找到 iterator 的定义:
Alt 05

    我们发现, 它是隶属于 _Mybase 中的一个 iterator.
    而我们的 _Mybase 是 _Vector_alloc<_Vec_base_types<_Ty, _Alloc> > 

无法避免, 我们要来看一看 _Vec_base_types 是什么鬼了...
Alt 06

    很崩溃, 简言之, 是一些东西的包装.
    看看那个长长的typedef......
    总之, 这货是一个包装器.
    需要注意的是, 我们的 _Wrap_alloc 是一个模板类, 是分配器中的类.
    它被定义为 _Alty, 也就是分配器类型.
    然后, 我们的_Val_types中就包含了 分配器 中定义的 pointer, reference 等.

好的, 我们先暂时忘掉 _Vec_base_types, 看看我们的 _Vector_alloc 模板类.
Alt 07

    赞, 终于看到了iterator了.
    可以看到iterator的原型是 _Vector_iterator<_Vector_val<_Val_types> > 
    我们先看一眼 _Vector_val

Alt 08

    可以看到, _Vector_val 中定义了我们的 first, last, end
    是不是和我们迭代器的 begin() end() 有点相似呢?

在来看看 _Vector_iterator 这个模板类
Alt 09

    可以看到, 这就是我们的iterator的实现类了.
    它继承自我们的  _Vector_const_iterator 类.
    也就是说, iterator 继承自 const_iterator 

我们还发现, vector的迭代器实现了 operator[]

Visual Studio 中的list的迭代器

跟踪方法相同, 在此不再多说, 直接给出寻找的截图.
Alt 10

Alt 11

Alt 12

我们又发现, list的迭代器又没有 operator[]

总结

vector的operator=的语义问题

在SGI中, vector的iterator是一个指针, 指针可以直接赋值.
而在VS中, vector的iterator并不是一个指针, 而是一个对象.
我们查看一下 begin() 方法, 就会发现:

iterator begin() _NOEXCEPT
    {    // return iterator for beginning of mutable sequence
    return (iterator(this->_Myfirst(), _STD addressof(this->_Get_data())));
    }

它是以对象来返回的, 会构建一个iterator的临时对象.
此时, 如下例子:

#include <vector>

int main()
{
    std::vector<int> demo;
    std::vector<int>::iterator it;
    it = demo.begin();

    return 0;
}

在执行 it = demo.begin() 的时候, 会调用 iterator 的默认 operator= 方法.
也就是说, 只会把_Ptr的地址拷贝到it的_Ptr中.
这是一个浅拷贝.
因为iterator指向的是我们容器中的一个元素, 这种浅拷贝的语义是正确的!

未完待续...

如有错误,请提出指正!谢谢.

回复