STL源码剖析

目录

一,容器

1,vector

2,list

3,deque

4,stack

5,queue

6,priority_queue

7,_Tree

8,map、multimap、set、multiset

9,_Hash

10,unordered_map、unordered_multimap、unordered_set、unordered_multiset

二,容器模板参数

1,class _Alloc = allocator<_Ty>

2,class _Container = deque<_Ty>

3,class _Pr = less

4,class _Hasher = hash<_Kty>

5,class _Keyeq = equal_to<_Kty>

三,迭代器

1,traits

2,迭代器类型


一,容器

1,vector

(1)_Vector_val

template<class _Val_types>
	class _Vector_val
		: public _Container_base
	{	// base class for vector to hold data
public:
	using value_type = typename _Val_types::value_type;
	using size_type = typename _Val_types::size_type;
	using difference_type = typename _Val_types::difference_type;
	using pointer = typename _Val_types::pointer;
	using const_pointer = typename _Val_types::const_pointer;
	using reference = value_type&;
	using const_reference = const value_type&;

	_Vector_val()
		: _Myfirst(),
		_Mylast(),
		_Myend()
		{	// initialize values
		}

	pointer _Myfirst;	// pointer to beginning of array
	pointer _Mylast;	// pointer to current end of sequence
	pointer _Myend;	// pointer to end of array
	};

这里面只存了指针

(2)_Vector_alloc

template<class _Alloc_types>
	class _Vector_alloc
	{	// base class for vector to hold allocator
public:
	using _Alty = typename _Alloc_types::_Alty;
	using _Alty_traits = typename _Alloc_types::_Alty_traits;
	using _Alproxy = _Rebind_alloc_t<_Alty, _Container_proxy>;
	using _Alproxy_traits = allocator_traits<_Alproxy>;
	using _Val_types = typename _Alloc_types::_Val_types;

	using size_type = typename _Val_types::size_type;
	using difference_type = typename _Val_types::difference_type;
	using pointer = typename _Val_types::pointer;
	using const_pointer = typename _Val_types::const_pointer;

	using iterator = _Vector_iterator<_Vector_val<_Val_types>>;
	using const_iterator = _Vector_const_iterator<_Vector_val<_Val_types>>;
//一堆函数
private:
	_Compressed_pair<_Alty, _Vector_val<_Val_types>> _Mypair;
	};

这是分配器,有分配内存相关的操作,里面还存放着vector的指针

(3)vector

template<class _Ty,
	class _Alloc = allocator<_Ty>>
	class vector
		: public _Vector_alloc<_Vec_base_types<_Ty, _Alloc>>
	{	// varying size array of values
private:
	using _Mybase = _Vector_alloc<_Vec_base_types<_Ty, _Alloc>>;
	using _Alty = typename _Mybase::_Alty;
	using _Alty_traits = typename _Mybase::_Alty_traits;

public:
	static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>,
		_MISMATCHED_ALLOCATOR_MESSAGE("vector<T, Allocator>", "T"));

	using value_type = _Ty;
	using allocator_type = _Alloc;
	using pointer = typename _Mybase::pointer;
	using const_pointer = typename _Mybase::const_pointer;
	using reference = _Ty&;
	using const_reference = const _Ty&;
	using size_type = typename _Mybase::size_type;
	using difference_type = typename _Mybase::difference_type;
	using iterator = typename _Mybase::iterator;
	using const_iterator = typename _Mybase::const_iterator;
	using reverse_iterator = _STD reverse_iterator<iterator>;
	using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
//一堆函数
}

继承了_Vector_alloc

获取数据指针:

	_NODISCARD _Ty * data() noexcept
		{	// return address of first element
		return (_Unfancy_maybe_null(this->_Myfirst()));
		}

	_NODISCARD const _Ty * data() const noexcept
		{	// return address of first element
		return (_Unfancy_maybe_null(this->_Myfirst()));
		}

2,list

(1)_List_buy

template<class _Ty,
	class _Alloc>
	class _List_buy
		: public _List_alloc<_List_base_types<_Ty, _Alloc>>
	{	// base class for list to hold buynode/freenode functions
public:
	using _Mybase = _List_alloc<_List_base_types<_Ty, _Alloc>>;
	using typename _Mybase::_Alnode;
	using typename _Mybase::_Alnode_traits;
	using typename _Mybase::_Nodeptr;
	using typename _Mybase::_Node;

	_List_buy()
		: _Mybase()
		{	// default construct
		}

	template<class _Any_alloc,
		class = enable_if_t<!is_same_v<remove_cv_t<remove_reference_t<_Any_alloc>>, _List_buy>>>
		_List_buy(_Any_alloc&& _Al)
		: _Mybase(_STD forward<_Any_alloc>(_Al))
		{	// construct from allocator
		}

	template<class... _Valty>
		_Nodeptr _Buynode(_Nodeptr _Next, _Nodeptr _Prev, _Valty&&... _Val)
		{	// allocate a node and set links and value
		_Nodeptr _Pnode = this->_Buynode0(_Next, _Prev);
		_Alnode& _Al = this->_Getal();

		_TRY_BEGIN
		_Alnode_traits::construct(_Al,
			_STD addressof(_Pnode->_Myval),
			_STD forward<_Valty>(_Val)...);
		_CATCH_ALL
		_Al.deallocate(_Pnode, 1);
		_RERAISE;
		_CATCH_END

		return (_Pnode);
		}

	void _Freenode(_Nodeptr _Pnode)
		{	// give node back
		_Alnode& _Al = this->_Getal();
		_Alnode_traits::destroy(_Al, _STD addressof(_Pnode->_Myval));
		_Node::_Freenode0(_Al, _Pnode);
		}
	};

(2)list

template<class _Ty,
	class _Alloc = allocator<_Ty>>
	class list
		: public _List_buy<_Ty, _Alloc>
	{	// bidirectional linked list
public:
	static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>,
		_MISMATCHED_ALLOCATOR_MESSAGE("list<T, Allocator>", "T"));

	using _Mybase = _List_buy<_Ty, _Alloc>;
	using _Node = typename _Mybase::_Node;
	using _Nodeptr = typename _Mybase::_Nodeptr;
	using _Alnode = typename _Mybase::_Alnode;
	using _Alnode_traits = typename _Mybase::_Alnode_traits;

	using value_type = typename _Mybase::value_type;
	using allocator_type = _Alloc;
	using size_type = typename _Mybase::size_type;
	using difference_type = typename _Mybase::difference_type;
	using pointer = typename _Mybase::pointer;
	using const_pointer = typename _Mybase::const_pointer;
	using reference = value_type&;
	using const_reference = const value_type&;

	using iterator = typename _Mybase::iterator;
	using const_iterator = typename _Mybase::const_iterator;
	using _Unchecked_iterator = typename _Mybase::_Unchecked_iterator;
	using _Unchecked_const_iterator = typename _Mybase::_Unchecked_const_iterator;

	using reverse_iterator = _STD reverse_iterator<iterator>;
	using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
//一堆函数
}

3,deque

(1)_Deque_val

template<class _Val_types>
	class _Deque_val
		: public _Container_base12
	{	// base class for deque to hold data
public:
	using value_type = typename _Val_types::value_type;
	using size_type = typename _Val_types::size_type;
	using difference_type = typename _Val_types::difference_type;
	using pointer = typename _Val_types::pointer;
	using const_pointer = typename _Val_types::const_pointer;
	using reference = value_type&;
	using const_reference = const value_type&;
	using _Mapptr = typename _Val_types::_Mapptr;

	_Deque_val()
		: _Map(),
		_Mapsize(0),
		_Myoff(0),
		_Mysize(0)
		{	// initialize values
		}

	size_type _Getblock(size_type _Off) const
		{	// determine block from offset
			// NB: _Mapsize and _DEQUESIZ are guaranteed to be powers of 2
		return ((_Off / _DEQUESIZ) & (_Mapsize - 1));
		}

	_Mapptr _Map;		// pointer to array of pointers to blocks
	size_type _Mapsize;	// size of map array, zero or 2^N
	size_type _Myoff;	// offset of initial element
	size_type _Mysize;	// current length of sequence
	};

deque的数据模型是分段数组,每一段的长度是_DEQUESIZ,一共有_Mapsize段。

_Map是一个指针表,里面存放着最多_Mapsize个分段数组的地址。

所有分段数组逻辑上是连续的,形成一个逻辑上的大数组,调用_Getblock函数可以根据在这个大数组中的下标_Off,计算出所在分段数组是_Map中的第几个指针,从而完成随机寻址

因为第0个元素在大数组中的下标是_Myoff,所以第k个元素在大数组中的下标就是k+_Myoff就出来了。

_Mapsize and _DEQUESIZ are guaranteed to be powers of 2  只是为了保证性能。

(2)_Deque_alloc

template<class _Alloc_types>
	class _Deque_alloc
	{	// base class for deque to hold allocator
public:
	using _Alty = typename _Alloc_types::_Alty;
	using _Alty_traits = typename _Alloc_types::_Alty_traits;
	using _Alpty = typename _Alloc_types::_Alpty;
	using _Alpty_traits = typename _Alloc_types::_Alpty_traits;
	using _Alproxy = _Rebind_alloc_t<_Alty, _Container_proxy>;
	using _Alproxy_traits = allocator_traits<_Alproxy>;
	using _Val_types = typename _Alloc_types::_Val_types;

	using size_type = typename _Val_types::size_type;
	using difference_type = typename _Val_types::difference_type;
	using pointer = typename _Val_types::pointer;
	using const_pointer = typename _Val_types::const_pointer;
	using _Mapptr = typename _Val_types::_Mapptr;

	using iterator = _Deque_iterator<_Deque_val<_Val_types>>;
	using const_iterator = _Deque_const_iterator<_Deque_val<_Val_types>>;
	using _Unchecked_iterator = _Deque_unchecked_iterator<_Deque_val<_Val_types>>;
	using _Unchecked_const_iterator =     _Deque_unchecked_const_iterator<_Deque_val<_Val_types>>;
//一堆函数
private:
	_Compressed_pair<_Alty, _Deque_val<_Val_types>> _Mypair;
	};

(3)deque

template<class _Ty,
	class _Alloc = allocator<_Ty>>
	class deque
		: public _Deque_alloc<_Deque_base_types<_Ty, _Alloc>>
	{	// circular queue of pointers to blocks
private:
	using _Mybase = _Deque_alloc<_Deque_base_types<_Ty, _Alloc>>;

public:
	static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>,
		_MISMATCHED_ALLOCATOR_MESSAGE("deque<T, Allocator>", "T"));

	using allocator_type = _Alloc;

	using _Alty = typename _Mybase::_Alty;
	using _Alty_traits = typename _Mybase::_Alty_traits;
	using _Alpty = typename _Mybase::_Alpty;
	using _Alpty_traits = typename _Mybase::_Alpty_traits;
	using _Mapptr = typename _Mybase::_Mapptr;

	using value_type = _Ty;
	using size_type = typename _Mybase::size_type;
	using difference_type = typename _Mybase::difference_type;
	using pointer = typename _Mybase::pointer;
	using const_pointer = typename _Mybase::const_pointer;
	using reference = _Ty&;
	using const_reference = const _Ty&;

	using iterator = typename _Mybase::iterator;
	using const_iterator = typename _Mybase::const_iterator;
	using _Unchecked_iterator = typename _Mybase::_Unchecked_iterator;
	using _Unchecked_const_iterator = typename _Mybase::_Unchecked_const_iterator;

	using reverse_iterator = _STD reverse_iterator<iterator>;
	using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
	enum {_EEN_DS = _DEQUESIZ};	// helper for expression evaluator
//一堆函数
}

4,stack

template<class _Ty,
	class _Container = deque<_Ty> >
	class stack
	{	// LIFO queue implemented with a container
public:
	typedef _Container container_type;
	typedef typename _Container::value_type value_type;
	typedef typename _Container::size_type size_type;
	typedef typename _Container::reference reference;
	typedef typename _Container::const_reference const_reference;

	static_assert(is_same_v<_Ty, value_type>, "container adaptors require consistent types");

	stack() _NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>) // strengthened
		: c()
		{	// construct with empty container
		}

	explicit stack(const _Container& _Cont)
		: c(_Cont)
		{	// construct by copying specified container
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		explicit stack(const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>) // strengthened
		: c(_Al)
		{	// construct with allocator
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		stack(const stack& _Right, const _Alloc& _Al)
		: c(_Right.c, _Al)
		{	// construct by copying specified container
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		stack(const _Container& _Cont, const _Alloc& _Al)
		: c(_Cont, _Al)
		{	// construct by copying specified container
		}

	explicit stack(_Container&& _Cont)
			_NOEXCEPT_COND(is_nothrow_move_constructible_v<_Container>) // strengthened
		: c(_STD move(_Cont))
		{	// construct by moving specified container
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		stack(stack&& _Right, const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
		: c(_STD move(_Right.c), _Al)
		{	// construct by moving specified container
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		stack(_Container&& _Cont, const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
		: c(_STD move(_Cont), _Al)
		{	// construct by moving specified container
		}

	void push(value_type&& _Val)
		{	// insert element at beginning
		c.push_back(_STD move(_Val));
		}

	template<class... _Valty>
		decltype(auto) emplace(_Valty&&... _Val)
		{	// insert element at beginning
#if _HAS_CXX17
		return (c.emplace_back(_STD forward<_Valty>(_Val)...));
#else /* _HAS_CXX17 */
		c.emplace_back(_STD forward<_Valty>(_Val)...);
#endif /* _HAS_CXX17 */
		}

	_NODISCARD bool empty() const
		{	// test if stack is empty
		return (c.empty());
		}

	_NODISCARD size_type size() const
		{	// test length of stack
		return (c.size());
		}

	_NODISCARD reference top()
		{	// return last element of mutable stack
		return (c.back());
		}

	_NODISCARD const_reference top() const
		{	// return last element of nonmutable stack
		return (c.back());
		}

	void push(const value_type& _Val)
		{	// insert element at end
		c.push_back(_Val);
		}

	void pop()
		{	// erase last element
		c.pop_back();
		}

	const _Container& _Get_container() const
		{	// get reference to container
		return (c);
		}

	void swap(stack& _Right) _NOEXCEPT_COND(_Is_nothrow_swappable<_Container>::value)
		{	// exchange contents with _Right
		_Swap_adl(c, _Right.c);
		}

protected:
	_Container c;	// the underlying container
	};

默认实现就是对deque的简单封装。

5,queue

template<class _Ty,
	class _Container = deque<_Ty> >
	class queue
	{	// FIFO queue implemented with a container
public:
	typedef _Container container_type;
	typedef typename _Container::value_type value_type;
	typedef typename _Container::size_type size_type;
	typedef typename _Container::reference reference;
	typedef typename _Container::const_reference const_reference;

	static_assert(is_same_v<_Ty, value_type>, "container adaptors require consistent types");

	queue() _NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>) // strengthened
		: c()
		{	// construct with empty container
		}

	explicit queue(const _Container& _Cont)
		: c(_Cont)
		{	// construct by copying specified container
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		explicit queue(const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>) // strengthened
		: c(_Al)
		{	// construct with empty container, allocator
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		queue(const _Container& _Cont, const _Alloc& _Al)
		: c(_Cont, _Al)
		{	// construct by copying specified container, allocator
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		queue(const queue& _Right, const _Alloc& _Al)
		: c(_Right.c, _Al)
		{	// construct by copying _Right container, allocator
		}

	explicit queue(_Container&& _Cont)
			_NOEXCEPT_COND(is_nothrow_move_constructible_v<_Container>) // strengthened
		: c(_STD move(_Cont))
		{	// construct by moving specified container
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		queue(_Container&& _Cont, const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
		: c(_STD move(_Cont), _Al)
		{	// construct by moving specified container, allocator
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		queue(queue&& _Right, const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
		: c(_STD move(_Right.c), _Al)
		{	// construct by moving _Right container, allocator
		}

	void push(value_type&& _Val)
		{	// insert element at beginning
		c.push_back(_STD move(_Val));
		}

	template<class... _Valty>
		decltype(auto) emplace(_Valty&&... _Val)
		{	// insert element at beginning
#if _HAS_CXX17
		return (c.emplace_back(_STD forward<_Valty>(_Val)...));
#else /* _HAS_CXX17 */
		c.emplace_back(_STD forward<_Valty>(_Val)...);
#endif /* _HAS_CXX17 */
		}

	_NODISCARD bool empty() const
		{	// test if queue is empty
		return (c.empty());
		}

	_NODISCARD size_type size() const
		{	// return length of queue
		return (c.size());
		}

	_NODISCARD reference front()
		{	// return first element of mutable queue
		return (c.front());
		}

	_NODISCARD const_reference front() const
		{	// return first element of nonmutable queue
		return (c.front());
		}

	_NODISCARD reference back()
		{	// return last element of mutable queue
		return (c.back());
		}

	_NODISCARD const_reference back() const
		{	// return last element of nonmutable queue
		return (c.back());
		}

	void push(const value_type& _Val)
		{	// insert element at beginning
		c.push_back(_Val);
		}

	void pop()
		{	// erase element at end
		c.pop_front();
		}

	const _Container& _Get_container() const
		{	// get reference to container
		return (c);
		}

	void swap(queue& _Right)
		_NOEXCEPT_COND(_Is_nothrow_swappable<_Container>::value)
		{	// exchange contents with _Right
		_Swap_adl(c, _Right.c);
		}

protected:
	_Container c;	// the underlying container
	};

默认实现就是对deque的简单封装。

6,priority_queue

template<class _Ty,
	class _Container = vector<_Ty>,
	class _Pr = less<typename _Container::value_type> >
	class priority_queue
	{	// priority queue implemented with a _Container
public:
	typedef _Container container_type;
	typedef _Pr value_compare;
	typedef typename _Container::value_type value_type;
	typedef typename _Container::size_type size_type;
	typedef typename _Container::reference reference;
	typedef typename _Container::const_reference const_reference;

	static_assert(is_same_v<_Ty, value_type>, "container adaptors require consistent types");

	priority_queue()
		_NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>
			&& is_nothrow_default_constructible_v<value_compare>) // strengthened
		: c(), comp()
		{	// construct with empty container, default comparator
		}

	explicit priority_queue(const _Pr& _Pred)
		_NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>
			&& is_nothrow_copy_constructible_v<value_compare>) // strengthened
		: c(), comp(_Pred)
		{	// construct with empty container, specified comparator
		}

	priority_queue(const _Pr& _Pred, const _Container& _Cont)
		: c(_Cont), comp(_Pred)
		{	// construct by copying specified container, comparator
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _InIt>
		priority_queue(_InIt _First, _InIt _Last)
		: c(_First, _Last), comp()
		{	// construct by copying [_First, _Last), default comparator
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _InIt>
		priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred)
		: c(_First, _Last), comp(_Pred)
		{	// construct by copying [_First, _Last), specified comparator
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _InIt>
		priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, const _Container& _Cont)
		: c(_Cont), comp(_Pred)
		{	// construct by copying [_First, _Last), container, and comparator
		c.insert(c.end(), _First, _Last);
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		explicit priority_queue(const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>
				&& is_nothrow_default_constructible_v<value_compare>) // strengthened
		: c(_Al), comp()
		{	// construct with empty container, allocator
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		priority_queue(const _Pr& _Pred, const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>
				&& is_nothrow_copy_constructible_v<value_compare>) // strengthened
		: c(_Al), comp(_Pred)
		{	// construct with empty container, comparator, allocator
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		priority_queue(const _Pr& _Pred, const _Container& _Cont, const _Alloc& _Al)
		: c(_Cont, _Al), comp(_Pred)
		{	// construct by copying specified container, comparator, allocator
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		priority_queue(const priority_queue& _Right, const _Alloc& _Al)
		: c(_Right.c, _Al), comp(_Right.comp)
		{	// construct by copying _Right, allocator
		}

	priority_queue(const _Pr& _Pred, _Container&& _Cont)
		: c(_STD move(_Cont)), comp(_Pred)
		{	// construct by moving specified container, comparator
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _InIt>
		priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, _Container&& _Cont)
		: c(_STD move(_Cont)), comp(_Pred)
		{	// construct by copying [_First, _Last), moving container
		c.insert(c.end(), _First, _Last);
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		priority_queue(const _Pr& _Pred, _Container&& _Cont, const _Alloc& _Al)
		: c(_STD move(_Cont), _Al), comp(_Pred)
		{	// construct by moving specified container, comparator, allocator
		_STD make_heap(c.begin(), c.end(), comp);
		}

	template<class _Alloc,
		class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
		priority_queue(priority_queue&& _Right, const _Alloc& _Al)
			_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>
				&& is_nothrow_move_constructible_v<value_compare>) // strengthened
		: c(_STD move(_Right.c), _Al), comp(_STD move(_Right.comp))
		{	// construct by moving _Right, allocator
		}

	void push(value_type&& _Val)
		{	// insert element at beginning
		c.push_back(_STD move(_Val));
		_STD push_heap(c.begin(), c.end(), comp);
		}

	template<class... _Valty>
		void emplace(_Valty&&... _Val)
		{	// insert element at beginning
		c.emplace_back(_STD forward<_Valty>(_Val)...);
		_STD push_heap(c.begin(), c.end(), comp);
		}

	_NODISCARD bool empty() const
		{	// test if queue is empty
		return (c.empty());
		}

	_NODISCARD size_type size() const
		{	// return length of queue
		return (c.size());
		}

	_NODISCARD const_reference top() const
		{	// return highest-priority element
		return (c.front());
		}

	void push(const value_type& _Val)
		{	// insert value in priority order
		c.push_back(_Val);
		_STD push_heap(c.begin(), c.end(), comp);
		}

	void pop()
		{	// erase highest-priority element
		_STD pop_heap(c.begin(), c.end(), comp);
		c.pop_back();
		}

	void swap(priority_queue& _Right)
		_NOEXCEPT_COND(_Is_nothrow_swappable<_Container>::value
			&& _Is_nothrow_swappable<_Pr>::value)
		{	// exchange contents with _Right
		_Swap_adl(c, _Right.c);
		_Swap_adl(comp, _Right.comp);
		}

protected:
	_Container c;	// the underlying container
	_Pr comp;	// the comparator functor
	};

原理是用二叉堆实现优先队列。

7,_Tree

template<class _Traits>
	class _Tree
		: public _Tree_comp_alloc<_Traits>
	{	// ordered red-black tree for map/multimap/set/multiset
// 省略
    }

从注释看,这是红黑树的实现,map/multimap/set/multiset都是对它的封装。

红黑树分为不带重复元素的,可以带重复元素的,两种红黑树。

map/set是不带重复元素的红黑树,multimap/multiset是可以带重复元素的红黑树。

8,map、multimap、set、multiset

map

template<class _Kty,
	class _Ty,
	class _Pr = less<_Kty>,
	class _Alloc = allocator<pair<const _Kty, _Ty>>>
	class map
		: public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>>
	{	// ordered red-black tree of {key, mapped} values, unique keys
//省略
	};

随机访问:

	mapped_type& operator[](key_type&& _Keyval)
		{	// find element matching _Keyval or insert with default mapped
		return (try_emplace(_STD move(_Keyval)).first->second);
		}

multimap

template<class _Kty,
	class _Ty,
	class _Pr = less<_Kty>,
	class _Alloc = allocator<pair<const _Kty, _Ty>>>
	class multimap
		: public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, true>>
	{	// ordered red-black tree of {key, mapped} values, non-unique keys
//省略
	};

multimap不提供随机访问的方法。

红黑树只根据key作为比较大小的依据,不看value,所以不同的key映射同一个value显然是可以的。

multimap支持同一个key映射多个value,这其中还允许有重复的value,即multimap支持完全重复的pair。

set

template<class _Kty,
	class _Pr = less<_Kty>,
	class _Alloc = allocator<_Kty>>
	class set
		: public _Tree<_Tset_traits<_Kty, _Pr, _Alloc, false>>
	{	// ordered red-black tree of key values, unique keys
//省略
	};

multiset

template<class _Kty,
	class _Pr = less<_Kty>,
	class _Alloc = allocator<_Kty>>
	class multiset
		: public _Tree<_Tset_traits<_Kty, _Pr, _Alloc, true>>
	{	// ordered red-black tree of key values, non-unique keys
//省略
	};

怎么理解multi?

先写个demo测一下:

int main()
{
	multimap<int,int> m;
	m.insert({ 1,2 });
	m.insert({ 1,3 });
	m.insert({ 3,3 });
	m.insert({ 1,2 });
	for (auto it : m) {
		cout << it.first << " " << it.second << endl;
	}
	multiset<int>s;
	s.insert(2);
	s.insert(3);
	s.insert(2);
	for (auto x : s) {
		cout << x << endl;
	}
	return 0;
}

输出:

1 2
1 3
1 2
3 3
2
2
3

也就是说,multiset是带重复元素的红黑树,所以2 3 2会变成2 2 3,

而multimap显然是这4个里面最复杂的,key由红黑树组成,所以前3个key是1 1 1,第4个key是2

但是{ 1,2 }{ 1,3 }{ 1,2 }这3个节点会保留顺序,不会排序,因为value是不带比较函数的。

也就是说,multimap相当于是每个键值对的值,其实都是一个线性表。

9,_Hash

template<class _Traits>
	class _Hash
	{	// hash table -- list with vector of iterators for quick access
public:
	using key_type = typename _Traits::key_type;
	using key_compare = typename _Traits::key_compare;
	using value_compare = typename _Traits::value_compare;
//省略
	_Traits _Traitsobj;	// traits to customize behavior
	_Mylist _List;	// list of elements, must initialize before _Vec
	_Myvec _Vec;	// vector of list iterators, begin() then end()-1
	size_type _Mask;	// the key mask
	size_type _Maxidx;	// current maximum key value
	};

C++哈希表用链接法处理冲突。

JAVA的哈希表是当链表长度达到阈值时自动转成红黑树。

10,unordered_map、unordered_multimap、unordered_set、unordered_multiset

这四个都是对_Hash的封装。

unordered_map

template<class _Kty,
	class _Ty,
	class _Hasher = hash<_Kty>,
	class _Keyeq = equal_to<_Kty>,
	class _Alloc = allocator<pair<const _Kty, _Ty>>>
	class unordered_map
		: public _Hash<_Umap_traits<_Kty, _Ty,
			_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>>
	{	// hash table of {key, mapped} values, unique keys
//省略
	};

unordered_multimap

template<class _Kty,
	class _Ty,
	class _Hasher = hash<_Kty>,
	class _Keyeq = equal_to<_Kty>,
	class _Alloc = allocator<pair<const _Kty, _Ty>>>
	class unordered_multimap
		: public _Hash<_Umap_traits<_Kty, _Ty,
			_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, true>>
	{	// hash table of {key, mapped} values, non-unique keys
//省略
	};

unordered_set

template<class _Kty,
	class _Hasher = hash<_Kty>,
	class _Keyeq = equal_to<_Kty>,
	class _Alloc = allocator<_Kty>>
	class unordered_set
		: public _Hash<_Uset_traits<_Kty,
			_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>>
	{	// hash table of key values, unique keys
//省略
	};

unordered_multiset

template<class _Kty,
	class _Hasher = hash<_Kty>,
	class _Keyeq = equal_to<_Kty>,
	class _Alloc = allocator<_Kty>>
	class unordered_multiset
		: public _Hash<_Uset_traits<_Kty,
			_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, true>>
	{	// hash table of key values, non-unique keys
//省略
	};

泛型哈希表的思路是二次哈希,首先把任意类型的key通过_Hasher映射成整数,再用_Hash处理整数的哈希存储问题。

可以把2个哈希函数看成复合函数,就变成了1个哈希函数,无论是谁有哈希冲突都无所谓,总体上肯定是有冲突的。

_Keyeq就是用来判断冲突的key是不是同一个key。

二,容器模板参数

除了容器中的元素本身类型的参数之外,还有如下参数。

1,class _Alloc = allocator<_Ty>(分配器)

2,class _Container = deque<_Ty>

3,class _Pr = less<typename _Container::value_type>

4,class _Hasher = hash<_Kty>

这是选择哈希函数,默认的是通用的hash函数。

hash函数的内部实现很粗暴,就是把数据强制转换成整数。

5,class _Keyeq = equal_to<_Kty>

这是哈希表中判断2个键是否相等的函数,默认的是通用的equal_to函数。

equal_to函数的内部实现很简单,就是调用==即可。

三,迭代器

1,traits

通用traits

template<class,
	class = void>
	struct _Iterator_traits_base
	{	// empty for non-iterators
	};

template<class _Iter>
	struct _Iterator_traits_base<_Iter, void_t<
		typename _Iter::iterator_category,
		typename _Iter::value_type,
		typename _Iter::difference_type,
		typename _Iter::pointer,
		typename _Iter::reference
		>>
	{	// defined if _Iter::* types exist
	using iterator_category = typename _Iter::iterator_category;
	using value_type = typename _Iter::value_type;
	using difference_type = typename _Iter::difference_type;

	using pointer = typename _Iter::pointer;
	using reference = typename _Iter::reference;
	};

template<class _Iter>
	struct iterator_traits
		: _Iterator_traits_base<_Iter>
	{	// get traits from iterator _Iter, if possible
	};

指针类型的

template<class _Ty,
	bool = is_object_v<_Ty>>
	struct _Iterator_traits_pointer_base
	{	// iterator properties for pointers to object
	using iterator_category = random_access_iterator_tag;
	using value_type = remove_cv_t<_Ty>;
	using difference_type = ptrdiff_t;

	using pointer = _Ty *;
	using reference = _Ty&;
	};

template<class _Ty>
	struct _Iterator_traits_pointer_base<_Ty, false>
	{	// iterator properties for pointers to non-object
		// not actually iterators, as no arithmetic is possible -> no members
	};

template<class _Ty>
	struct iterator_traits<_Ty *>
		: _Iterator_traits_pointer_base<_Ty>
	{	// get traits from pointer, if possible
	};

iterator_category是允许的操作集,

value_type是数据的类型

difference_type表示2个迭代器的差值,其实就是有符号整数类型,ptrdiff_t也是有符号整数类型。

pointer 和 reference 是数据的指针类型和引用类型。

2,迭代器类型

 对应的空结构体:

struct input_iterator_tag
	{	// identifying tag for input iterators
	};

struct output_iterator_tag
	{	// identifying tag for output iterators
	};

struct forward_iterator_tag
	: input_iterator_tag
	{	// identifying tag for forward iterators
	};

struct bidirectional_iterator_tag
	: forward_iterator_tag
	{	// identifying tag for bidirectional iterators
	};

struct random_access_iterator_tag
	: bidirectional_iterator_tag
	{	// identifying tag for random-access iterators
	};

用显式的结构体来表达迭代器类型,可以直接用于函数重载。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值