Today, I was asked a question by my colleagues. What is the third parameter in map? So I wrote the following program to test it.
#include <map>#include <iostream>using namespace std;typedef map<int,char> icMap;typedef map<int,char>::iterator It;class func{public:func(){};bool operator ()( const int i1, const int i2 ){return i1>i2;}};typedef map<int,char,func> icMapCmp;typedef map<int,char,func>::iterator It1;int main(void){icMap m;m.insert(make_pair(1,'1'));m.insert(make_pair(3,'3'));m.insert(make_pair(2,'2'));for (It it = m.begin();it!=m.end();++it){cout<<it->first<<"\t"<<it->second<<endl;}icMapCmp c;c.insert(make_pair(1,'1'));c.insert(make_pair(3,'3'));c.insert(make_pair(2,'2'));for (It1 it1 = c.begin();it1!=c.end();++it1){cout<<it1->first<<"\t"<<it1->second<<endl;}return 0;}
The third parameter msdn is explained as follows:
Traits
The type that provides a function object that can compare two element values as sort keys to determine their relative order in the map. this argument is optional and the binary predicate less <key> is the default value.
As mentioned in msdn, the default value is STD: less.
See the definition of map in stl_map.h:
Template <typename _ key, typename _ TP, typename _ compare = STD: less <_ key>,
Typename _ alloc = STD: Allocator <STD: pair <const _ key, _ TP>
Class Map
The default compare is indeed STD: less, STD: less. In stl_function.h, STD: less is implemented as follows:
template <class _Tp> struct less : public binary_function<_Tp, _Tp, bool> { bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }};
Return _ x <_ y; originally. However, this is only a comparison function. After comparison, how does MAP handle it? It seems that the root cause is still not found.
Then continue tracing. The map constructor:
Map ()
: _ M_t (_ compare (), allocator_type ()){}
When _ M_t is initialized with _ compare (), the _ M_t will be tracked and the red and black trees inside the map will be tracked.
Typedef _ rb_tree <key_type, value_type, _ select1st <value_type>,
Key_compare, _ pair_alloc_type> _ rep_type;
/// @ If Maint the actual tree structure. @ endif
_ Rep_type _ M_t;
Finally, the insert_unique function is used:
template<typename _Key, typename _Val, typename _KeyOfValue, typename _Compare, typename _Alloc> pair<typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: insert_unique(const _Val& __v) { _Link_type __x = _M_begin(); _Link_type __y = _M_end(); bool __comp = true; while (__x != 0){ __y = __x; __comp = _M_impl._M_key_compare(_KeyOfValue()(__v), _S_key(__x)); __x = __comp ? _S_left(__x) : _S_right(__x);} iterator __j = iterator(__y); if (__comp)if (__j == begin()) return pair<iterator,bool>(_M_insert(__x, __y, __v), true);else --__j; if (_M_impl._M_key_compare(_S_key(__j._M_node), _KeyOfValue()(__v)))return pair<iterator, bool>(_M_insert(__x, __y, __v), true); return pair<iterator, bool>(__j, false);}
The returned value type definition before the function is a bit complicated. In fact, the pair <iterator, bool> is returned, and then compared according to the value _ V to be inserted. If it is true, search for it on the left, or search for it on the right.
template<typename _Key, typename _Val, typename _KeyOfValue, typename _Compare, typename _Alloc> typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: _M_insert(_Base_ptr __x, _Base_ptr __p, const _Val& __v) { bool __insert_left = (__x != 0 || __p == _M_end() || _M_impl._M_key_compare(_KeyOfValue()(__v), _S_key(__p))); _Link_type __z = _M_create_node(__v); _Rb_tree_insert_and_rebalance(__insert_left, __z, __p, this->_M_impl._M_header); ++_M_impl._M_node_count; return iterator(__z); }
After finding the position, create a node and insert it into the binary balancing tree (that is, the red and black trees.
Hahaha, _ rb_tree_insert_and_rebalance cannot find the code. The following code is found in stlport.
template <class _Key, class _Value, class _KeyOfValue, class _Compare, class _Alloc> __iterator__ _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc> ::_M_insert(_Rb_tree_node_base* __x_, _Rb_tree_node_base* __y_, const _Value& __v, _Rb_tree_node_base* __w_){ _Link_type __w = (_Link_type) __w_; _Link_type __x = (_Link_type) __x_; _Link_type __y = (_Link_type) __y_; _Link_type __z; if ( __y == this->_M_header._M_data || ( __w == 0 && // If w != 0, the remainder fails to false ( __x != 0 || // If x != 0, the remainder succeeds to true _M_key_compare( _KeyOfValue()(__v), _S_key(__y) ) ) ) ) { __z = _M_create_node(__v); _S_left(__y) = __z; // also makes _M_leftmost() = __z // when __y == _M_header if (__y == this->_M_header._M_data) { _M_root() = __z; _M_rightmost() = __z; } else if (__y == _M_leftmost()) _M_leftmost() = __z; // maintain _M_leftmost() pointing to min node } else { __z = _M_create_node(__v); _S_right(__y) = __z; if (__y == _M_rightmost()) _M_rightmost() = __z; // maintain _M_rightmost() pointing to max node } _S_parent(__z) = __y; _S_left(__z) = 0; _S_right(__z) = 0; _Rb_global_inst::_Rebalance(__z, this->_M_header._M_data->_M_parent); ++_M_node_count; return iterator(__z);}