STL源码剖析(十四)关联式容器之set、map、multiset、multimap

set特性
set所有元素都会根据元素的键值自动被排序,set元素的键值就是实值,实值就是键值。
set不可通过迭代器修改set元素值,set元素值就是其键值,关系到set元素的排列规则,源码中set<T>::iterator被定义为底层RB-tree的const_iterator,杜绝写入操作。
STL特别提供了一组set/mulset的相关算法,包括交集set_intersection、联集set_union、差集set_difference、对称差集set_symmetric_difference。

set与list相同的性质:元素新增(insert)和删除(erase)操作时,操作之前的所有迭代器,在操作之后依然有效,被删除元素的迭代器除外。

set以RB-tree为底层机制,set开放的各种接口几乎是转调用RB-tree的操作行为。

map特性
所有元素会根据元素的键值自动被排序,map的所有元素都是pair,同时拥有键值key和实值value,map元素键值不可相同。

map的键值不可修改,实值可以修改,因此map的迭代器既不是constant iterators,也不是mutable iterators。
map与list相同的性质:元素新增(insert)和删除(erase)时,操作之前的所有迭代器,在操作之后依然有效,被删除元素的迭代器除外。

map以RB-tree为底层机制,map开放的各种接口几乎是转调用RB-tree的操作行为。

插入操作,返回一个pair,第一个元素是个迭代器,指向插入成功的新元素或插入失败键值重复的旧元素,第二个元素返回插入成功或失败的bool值。
下标运算符,用法有两种,可能作为左值运用内容可被修改,也可能作为右值使用内容不可被修改。
下标运算符,先插入键值和临时实值对象,插入操作返回一个pair,第一个元素是个迭代器,指向插入成功的新元素或插入失败(键值重复)的旧元素。下标运算符作为左值使用时,正好赋值新插入点实值;下标运算作右值使用时,返回插入失败键值重复旧元素的实值。

multiset特性
multiset特性和用法与set完全相同,唯一差别在于它允许键值重复,因此它的插入操作采用的是底层RT-tree的insert_equal()而不是insert_unique()。

multimap
multimap的特性和用法与map完全相同,唯一差别在于它允许键值重复,因此它的插入操作采用的是底层RT-tree的insert_equal()而不是insert_unique()。

下面stl_pari的pair定义

namespace std _GLIBCXX_VISIBILITY(default)
{
  /// piecewise_construct_t
  struct piecewise_construct_t { };
  constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();

  // Forward declarations.
  template<typename...>
    class tuple;

  template<std::size_t...>
    struct _Index_tuple;

  template<class _T1, class _T2>
    struct pair
    {
      typedef _T1 first_type;    /// @c first_type is the first bound type
      typedef _T2 second_type;   /// @c second_type is the second bound type

      _T1 first;                 /// @c first is a copy of the first object
      _T2 second;                /// @c second is a copy of the second object

      _GLIBCXX_CONSTEXPR pair() //默认构造函数
      : first(), second() { }

      _GLIBCXX_CONSTEXPR pair(const _T1& __a, const _T2& __b)
      : first(__a), second(__b) { }

      /** There is also a templated copy ctor for the @c pair class itself.  */
      template<class _U1, class _U2, class = typename
	       enable_if<__and_<is_convertible<const _U1&, _T1>,
				is_convertible<const _U2&, _T2>>::value>::type>
	constexpr pair(const pair<_U1, _U2>& __p)
	: first(__p.first), second(__p.second) { }

      constexpr pair(const pair&) = default;
      constexpr pair(pair&&) = default;

      template<class _U1, class = typename
	       enable_if<is_convertible<_U1, _T1>::value>::type>
	constexpr pair(_U1&& __x, const _T2& __y)
	: first(std::forward<_U1>(__x)), second(__y) { }

      template<class _U2, class = typename
	       enable_if<is_convertible<_U2, _T2>::value>::type>
	constexpr pair(const _T1& __x, _U2&& __y)
	: first(__x), second(std::forward<_U2>(__y)) { }

      template<class _U1, class _U2, class = typename
	       enable_if<__and_<is_convertible<_U1, _T1>,
				is_convertible<_U2, _T2>>::value>::type>
	constexpr pair(_U1&& __x, _U2&& __y)
	: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }

      template<class _U1, class _U2, class = typename
	       enable_if<__and_<is_convertible<_U1, _T1>,
				is_convertible<_U2, _T2>>::value>::type>
	constexpr pair(pair<_U1, _U2>&& __p)
	: first(std::forward<_U1>(__p.first)),
	  second(std::forward<_U2>(__p.second)) { }

      template<typename... _Args1, typename... _Args2>
        pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);

      pair&
      operator=(const pair& __p)
      {
		first = __p.first;
		second = __p.second;
		return *this;
      }

      pair&
      operator=(pair&& __p)
      noexcept(__and_<is_nothrow_move_assignable<_T1>,
	              is_nothrow_move_assignable<_T2>>::value)
      {
		first = std::forward<first_type>(__p.first);
		second = std::forward<second_type>(__p.second);
		return *this;
      }

      template<class _U1, class _U2>
	pair&
	operator=(const pair<_U1, _U2>& __p)
	{
	  first = __p.first;
	  second = __p.second;
	  return *this;
	}

      template<class _U1, class _U2>
	pair&
	operator=(pair<_U1, _U2>&& __p)
	{
	  first = std::forward<_U1>(__p.first);
	  second = std::forward<_U2>(__p.second);
	  return *this;
	}

      void
      swap(pair& __p)
      noexcept(noexcept(swap(first, __p.first))
	       && noexcept(swap(second, __p.second)))
      {
		using std::swap;
		swap(first, __p.first);
		swap(second, __p.second);
      }

    private:
      template<typename... _Args1, std::size_t... _Indexes1,
               typename... _Args2, std::size_t... _Indexes2>
        pair(tuple<_Args1...>&, tuple<_Args2...>&,
             _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>);
    };

  /// Two pairs of the same type are equal iff their members are equal.
  template<class _T1, class _T2>
    inline _GLIBCXX_CONSTEXPR bool
    operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
    { return __x.first == __y.first && __x.second == __y.second; }

  template<class _T1, class _T2>
    inline _GLIBCXX_CONSTEXPR bool
    operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
    { return __x.first < __y.first
	     || (!(__y.first < __x.first) && __x.second < __y.second); }

  /// Uses @c operator== to find the result.
  template<class _T1, class _T2>
    inline _GLIBCXX_CONSTEXPR bool
    operator!=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
    { return !(__x == __y); }

  /// Uses @c operator< to find the result.
  template<class _T1, class _T2>
    inline _GLIBCXX_CONSTEXPR bool
    operator>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
    { return __y < __x; }

  /// Uses @c operator< to find the result.
  template<class _T1, class _T2>
    inline _GLIBCXX_CONSTEXPR bool
    operator<=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
    { return !(__y < __x); }

  /// Uses @c operator< to find the result.
  template<class _T1, class _T2>
    inline _GLIBCXX_CONSTEXPR bool
    operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
    { return !(__x < __y); }

  template<class _T1, class _T2>
    inline void
    swap(pair<_T1, _T2>& __x, pair<_T1, _T2>& __y)
    noexcept(noexcept(__x.swap(__y)))
    { __x.swap(__y); }


  template<class _T1, class _T2>
    constexpr pair<typename __decay_and_strip<_T1>::__type,
                   typename __decay_and_strip<_T2>::__type>
    make_pair(_T1&& __x, _T2&& __y)
    {
      typedef typename __decay_and_strip<_T1>::__type __ds_type1;
      typedef typename __decay_and_strip<_T2>::__type __ds_type2;
      typedef pair<__ds_type1, __ds_type2> 	      __pair_type;
      return __pair_type(std::forward<_T1>(__x), std::forward<_T2>(__y));
    }
} // namespace std
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值