STL源码剖析
选用SGI版本的STL源码来做讲解,编译器为GCC;
一、STL体系结构
STL提供六大组件,彼此可以组合套用:
- 容器 containers:各种数据结构,如vector,list等;
- 算法 algorithms:各种常用算法,如sort,search等;
- 迭代器 iterators:容器与算法间的胶合剂,即泛型指针;
- 仿函数 functors:行为类似函数,可作为算法的某种策略;
- 适配器 adapters:一种用来修饰容器、仿函数或迭代器接口的东西,例如STL提供的queue和stack看似容器,其实是一种容器适配器,所有操作都由底层deque实现;
- 内存分配器 allocators:负责空间配置与管理;
六大组件的交互关系如下图:
容器通过allocator获取存储空间,
算法通过迭代器存取容器内容,
仿函数协助算法完成不同的策略变化,
adaptor可以修饰或套接仿函数;
二、可能令人困惑的C++语法
- 临时对象的产生与使用:临时对象是一种无名对象,例如任何pass by value操作都会引发copy操作,就形成一个临时对象,造成效率上的负担。
但有时又刻意制造一些临时对象,可以使程序干净清爽。刻意制造临时对象的方法是在数据类型名之后加一对小括号,例如int(8),相当于调用构造函数且不指定变量名。
STL最常将此用于仿函数与算法的搭配上:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
template <typename T>
class print
{
public:
void operator()(const T &elem)
{ cout << elem << " "; }
};
int main()
{
int ia[6] = {0, 1, 2, 3, 4, 5};
vector<int> iv(ia, ia + 6);
//print<int>()是一个临时对象,而不是一个函数调用操作;
for_each(iv.begin(), iv.end(), print<int>());
}
-
++increament/–decrement/*dereference操作符
迭代器的前进,后退,取值操作符;
前进分为前置++和后置++,区别在于参数中多一个占位符;
后退也分为前置–和后置–,区别在于参数中多一个占位符; -
前闭后开区间表示法
即迭代器所表示的区间,以 [first, last) 来表示,整个范围从first开始,到 last - 1 结束,last实际上已经超出了实际的有效范围; -
函数调用操作符重载 ()
如果你对某个class进行operator()重载,它就成为一个仿函数;
#include <iostream>
using namespace std;
template <typename T>
struct mplus
{
operator() (const T& x, const T& y) const { return x + y; }
};
template <typename T>
struct mminus
{
operator() (const T& x, const T& y) const { return x - y; }
};
int main()
{
mplus<int> plusObj;
mminus<int> minusObj;
// 使用仿函数对象,类似函数调用
cout << plusObj(1, 2) << endl;
cout << minusObj(1, 2) << endl;
// 使用匿名对象
cout << mplus<int>()(1, 2) << endl;
cout << mminus<int>()(1, 2) << endl;
}