list和iterator

1. 容器之间的复合关系(composition)

如下图:

  • array
  • vector
    • heap
      • priority_queue
  • list
  • slist(标准库改为forward_list了)
  • deque
    • stack
    • queue

关联性容器先不说了. 注意到这是2.9的版本, 容器之间的关系不是继承, 而是复合关系.
在这里插入图片描述

2. list源码探究

如下图, 从图中右边我们分析一下源码:

template<class T, class Alloc= alloc>
class list;

的定义中, 我们知道list只有有一个成员变量node,类型是link_type, 而link_type的类型是list_node*的, 因此list的大小就是8个字节(32位机子).

再看一下list_node里面的成员变量, 其实是一个模板类__list_node<T>, 里面有三个成员变量, 分别是data, prev, next, 注意到prev, next是指向void的, 这其实不好的, 因此4.9版本改进了, 指向了本类(如__list_node).

当我们用iterator的时候, 我们会有iterator++的操作, 如下图, 如果没有重载++的话, 当使用iterator++的时候, 指针不会智能地指向下一个node中去, 因此我们需要重载operator++等运算符. 这种行为其实被封装在__list_iterator类模板里了, 这个类模板需要传入三个参数T, T&, T*(这其实也是没必要的, 后续版本只需要传入一个), 下面我们来看看封装了iterator++重载的函数干了啥.
在这里插入图片描述
如下图, 是__list_iterator类的部分代码, 这部分代码主要typedef了5个东西, 分别是

  1. iterator_category
  2. value_type
  3. pointer
  4. reference
  5. different_type

(其他两个先不管, 因为这5个后面会说)
然后 类中有一个node, 指向一个list节点, 如下图左边的图示, 接着重载了*, ->, 前置operator++()和后置++操作等…
在这里插入图片描述
下面是重载++的详解, 主要就是说明前置和后置的区别,
其中前置返回的是self&引用类型, 后置返回的是self类型, 因此才会有如下结论:

++++i ⇒ ++(++i)
i++++ => (i++)++  //error, 因为返回的不是引用类型, 不能继续操作
//返回的是一个右值, 右值是不可以被修改的

同时我注意到一个优先级的问题, 比如:

self tmp = *this;

由于CPP是从右往左执行的, 具体原因主要是函数压栈的问题, 可以看C/C++函数参数为何是从右到左?
但是要注意, 压栈顺序和参数计算顺序不一样, 详见C/C++函数参数列表变量的计算顺序
我简单举个例子:

void FuncB(int a, int b)
{
    cout << a << endl;
    cout << b << endl;
}
void FuncA()
{
    int i = 0;
    FuncB(++i, i++); //2, 0
}

上面的程序就是参数计算顺序的问题, 我的编译器是2和0, 但是不同的编译器对参数的计算顺序会不一样, 按照我的理解, FuncB先计算i++, 然后再计算++i, 于是便有了2和0.
在这里插入图片描述
下面是重载*和->运算符的例子, 没啥好说的
在这里插入图片描述

接下来对比一下2.9个4.9标准库list的改变:

  1. 可以看到typedef __list_iterator<T, T&, T*> itertator里面的模板参数变成了一个_Tp, G4.9进入__List_iterator里面再另外typedef一个引用和一个指针.
  2. __list_node节点也变了, 4.9中变成了_List_node, 里面只有一个_M_data, 并且继承于_List_node_base, 这里面有两个指向自己的指针, 对比2.9的指向void, 发生了改变.
    在这里插入图片描述

3. Iterator设计原则

如下图的rotate算法, 需要传入迭代器, 里面的__rotate还需要__iterator_category, 这个是算法在提问迭代器的类型是什么; 接着我们看__rotate里面的实现, 需要知道迭代器里面的different_typevalue_type(还有两种没有出现分别是referencepointer)
在这里插入图片描述
因此, 为了回答算法的提问, Iterator必须提供5种associated types
在这里插入图片描述
同时, 如果iterator不是class的话, 标准库又设计了Iterator traints来"萃取"类和指针相应的处理方式
下图的萃取机就是一个中介层, 把 指针类型T*const T*分在上面, iterator则在下面.
因为iterator如果是类的话, 会有能力定义自己的associated types, 但是指针并没有办法定义.
在这里插入图片描述
具体的iterator_traits实现如下:
如果I是class的话, 进入1, 如果I是指针的话, 进入2和3, 这是用偏特化来实现的.
需要注意是:
不管是T*还是const T*, iterator_traits里面都是定义typedef T value_type, 不带const的, 具体原因下图黄色部分解释了.
在这里插入图片描述
更具体的实现:
可以发现, 迭代器是类的 直接取类I中的即可, 如果是指针的则需要typedef新的名字.
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zedjay_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值