map
与set相同,map同样是以红黑树RB_Tree为底层机制的关联式容器。map的每一个元素都拥有两个值,一个键值(key)和一个实值(value)。它的内部实现是用一个pair来保存这个两个值。所以,map的每一个元素又是一个pair。下面是STL源码中stl_pair.h对pair的定义。
template <class T1, class T2>
struct pair {
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& a, const T2& b) : first(a), second(b) {}
#ifdef __STL_MEMBER_TEMPLATES
template <class U1, class U2>
pair(const pair<U1, U2>& p) : first(p.first), second(p.second) {}
#endif
};
因为map底层是一棵红黑树(RB_Tree),红黑树的又是一种平衡二叉搜索树,自动排序效果很好。因此map内所有的元素都会根据元素的键值(key)自动排序。这一点也限制了我们不能修改map内元素的键值(key),键值(key)关系到map元素的排列规则,任意改变map的元素键值将会严重破坏map组织结构。那么STL源码是如何限制我们呢?
打开stl_map.h,你会看到这么一句话:
typedef pair<const Key, T> value_type;
它将pair重命名成value_type,同时将pair的key声明成了const类型,限制我们不能对它做出修改。
map的底层是红黑树,map的各种操作接口红黑树也都提供了,所以几乎所有的map操作行为,都是调用红黑树RB_Tree的操作行为。下面我将从源码角度讲,map是如何调用红黑树的。
类型:“是你的又怎么样,我改个名字就是我的了”
请允许我用“不要脸”和“暴力”这两个名字来形容map在这里的做法,尽管它的整个实现都很“不要脸”。它先把红黑树重命名。再用重命名的红黑树把红黑树内的参数类型再次重命名。好像这样就变成自己的了,但的确是这样。
这里,我们可以明显感觉到STL库的
代码复用性是多么的高,它的编写者是多么的厉害。
源码:
private:
//将红黑树重命名
typedef rb_tree<key_type, value_type,
select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing map
public:
//再对类型重命名
typedef typename rep_type::pointer pointer;
typedef typename rep_type::const_pointer const_pointer;
typedef typename rep_type::reference reference;
typedef typename rep_type::const_reference const_reference;
typedef typename rep_type::iterator iterator;
typedef typename rep_type::const_iterator const_iterator;
typedef typename rep_type::reverse_iterator reverse_iterator;
typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
typedef typename rep_type::size_type size_type;
typedef typename rep_type::difference_type difference_type;
当然,它也可以有一些自己的东西。
源码:
typedef Key key_type;
typedef T data_type;
typedef T mapped_type;
typedef pair<const Key, T> value_type;
typedef Compare key_compare;
对象成员
map的源码里面对私有成员(private)的定义有以下四行:
private:
typedef rb_tree<key_type, value_type,select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing map
我们可以看到,它直接将一个红黑树类型rb_tree(它的模板参数不再讲,想了解的可以去看看rb_tree的源码)重命名成rep_ type,并且利用rep_ type构建了一个红黑树对象t。如果你接着往下看,你会发现,map的所有方法中都有t的身影。
方法
基本方法
这里我将构造,赋值运算符重载定义为基本方法。(纯属本人为了方便)
构造
打开c++Reference,会看到map的构造有三种实现。前两种是构造函数,第三种是拷贝构造函数。但是它远远没有表面上这么简单。
1.(构造)
explicit map(const Compare& comp = Compare(),const Allocator& =