C++ STL 容器设计与实现分析 -- array

1、array(C++11)

array 是固定长度的数组,定义时就指定长度,一旦定义长度不能更改(不能扩容)。

  template<typename _Tp, std::size_t _Nm>
    struct array
    {
      typedef _Tp                           value_type;
      typedef value_type*                  pointer;
      typedef const value_type*                       const_pointer;
      typedef value_type&                             reference;
      typedef const value_type&                       const_reference;
      typedef value_type*                        iterator;
      typedef const value_type*                  const_iterator;
      typedef std::size_t                              size_type;
      typedef std::ptrdiff_t                             difference_type;
      typedef std::reverse_iterator<iterator>          reverse_iterator;
      typedef std::reverse_iterator<const_iterator>   const_reverse_iterator;

      // Support for zero-sized arrays mandatory.
      typedef __array_traits<_Tp, _Nm> _AT_Type;
      typename _AT_Type::_Type                         _M_elems;
      /***/
  • array 有两个模板参数:元素类型和元素个数,元素个数可以是 0
  • pointer/reference/iterator 直接是元素类型相应类型

__array_traits 使用了模板偏特化支持 array 元素个数可以为 0。当元素个数为 0 时,定义了一个空类 _Type。_S_ref() 和 _S_ptr() 使用 nullptr 构造返回值。

  template<typename _Tp, std::size_t _Nm>
    struct __array_traits
    {
      typedef _Tp _Type[_Nm];
      typedef __is_swappable<_Tp> _Is_swappable;
      typedef __is_nothrow_swappable<_Tp> _Is_nothrow_swappable;

      static constexpr _Tp&
      _S_ref(const _Type& __t, std::size_t __n) noexcept
      { return const_cast<_Tp&>(__t[__n]); }

      static constexpr _Tp*
      _S_ptr(const _Type& __t) noexcept
      { return const_cast<_Tp*>(__t); }
    };

 template<typename _Tp>
   struct __array_traits<_Tp, 0>
   {
     struct _Type { };
     typedef true_type _Is_swappable;
     typedef true_type _Is_nothrow_swappable;

     static constexpr _Tp&
     _S_ref(const _Type&, std::size_t) noexcept
     { return *static_cast<_Tp*>(nullptr); }

     static constexpr _Tp*
     _S_ptr(const _Type&) noexcept
     { return nullptr; }
   };

1.1、data()

如果 array 元素个数为 0,data() 返回 nullptr,否则返回数组首地址。

      [[__gnu__::__const__, __nodiscard__]]
      _GLIBCXX17_CONSTEXPR pointer
      data() noexcept
      { return _AT_Type::_S_ptr(_M_elems); }

1.2、begin()/end()/front()/back()

begin() 和 end() 返回 iterator,从定义可知,迭代器就是原始指针。

      [[__gnu__::__const__, __nodiscard__]]
      _GLIBCXX17_CONSTEXPR iterator
      begin() noexcept
      { return iterator(data()); }

      [[__gnu__::__const__, __nodiscard__]]
      _GLIBCXX17_CONSTEXPR iterator
      end() noexcept
      { return iterator(data() + _Nm); }

front() 和 back() 返回的是 reference。非 const 和 const 类型实现不同,非 const 类型借助 begin() 和 end() 实现,而 const 类型使用 _S_ref() 实现。

      [[__nodiscard__]]
      _GLIBCXX17_CONSTEXPR reference
      front() noexcept
      {
    __glibcxx_requires_nonempty();
    return *begin();
      }

      [[__nodiscard__]]
      constexpr const_reference
      front() const noexcept
      {
#if __cplusplus >= 201402L
    __glibcxx_requires_nonempty();
#endif
    return _AT_Type::_S_ref(_M_elems, 0);
      }

      [[__nodiscard__]]
      _GLIBCXX17_CONSTEXPR reference
      back() noexcept
      {
    __glibcxx_requires_nonempty();
    return _Nm ? *(end() - 1) : *end();
      }

      [[__nodiscard__]]
      constexpr const_reference
      back() const noexcept
      {
#if __cplusplus >= 201402L
    __glibcxx_requires_nonempty();
#endif
    return _Nm ? _AT_Type::_S_ref(_M_elems, _Nm - 1)
                : _AT_Type::_S_ref(_M_elems, 0);
      }

1.3、operator[]/at

      // Element access.
      [[__nodiscard__]]
      _GLIBCXX17_CONSTEXPR reference
      operator[](size_type __n) noexcept
      {
    __glibcxx_requires_subscript(__n);
    return _AT_Type::_S_ref(_M_elems, __n);
      }

      _GLIBCXX17_CONSTEXPR reference
      at(size_type __n)
      {
    if (__n >= _Nm)
      std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
                        ">= _Nm (which is %zu)"),
                    __n, _Nm);
    return _AT_Type::_S_ref(_M_elems, __n);
      }
欢迎关注公众号“源知源为”,阅读更多技术干货
#C++##STL##容器#
C/C++基础 文章被收录于专栏

C/C++ 语言基础

全部评论

相关推荐

头像
10-13 18:10
已编辑
东南大学 C++
。收拾收拾心情下一家吧————————————————10.12更新上面不知道怎么的,每次在手机上编辑都会只有最后一行才会显示。原本不想写凉经的,太伤感情了,但过了一天想了想,凉经的拿起来好好整理,就像象棋一样,你进步最快的时候不是你赢棋的时候,而是在输棋的时候。那废话不多说,就做个复盘吧。一面:1,经典自我介绍2,项目盘问,没啥好说的,感觉问的不是很多3,八股问的比较奇怪,他会深挖性地问一些,比如,我知道MMU,那你知不知道QMMU(记得是这个,总之就是MMU前面加一个字母)4,知不知道slab内存分配器-&gt;这个我清楚5,知不知道排序算法,排序算法一般怎么用6,写一道力扣的,最长回文子串反问:1,工作内容2,工作强度3,关于友商的问题-&gt;后面这个问题问HR去了,和中兴有关,数通这个行业和友商相关的不要提,这个行业和别的行业不同,别的行业干同一行的都是竞争关系,数通这个行业的不同企业的关系比较微妙。特别细节的问题我确实不知道,但一面没挂我。接下来是我被挂的二面,先说说我挂在哪里,技术性问题我应该没啥问题,主要是一些解决问题思路上的回答,一方面是这方面我准备的不多,另一方面是这个面试写的是“专业面试二面”,但是感觉问的问题都是一些主管面/综合面才会问的问题,就是不问技术问方法论。我以前形成的思维定式就是专业面会就是会,不会就直说不会,但事实上如果问到方法论性质的问题的话得扯一下皮,不能按照上面这个模式。刚到位置上就看到面试官叹了一口气,有一些不详的预感。我是下午1点45左右面的。1,经典自我介绍2,你是怎么完成这个项目的,分成几个步骤。我大致说了一下。你有没有觉得你的步骤里面缺了一些什么,(这里已经在引导我往他想的那个方向走了),比如你一个人的能力永远是不够的,,,我们平时会有一些组内的会议来沟通我们的所思所想。。。。3,你在项目中遇到的最困难的地方在什么方面4,说一下你知道的TCP/IP协议网络模型中的网络层有关的协议......5,接着4问,你觉得现在的socket有什么样的缺点,有什么样的优化方向?6,中间手撕了一道很简单的快慢指针的问题。大概是在链表的倒数第N个位置插入一个节点。————————————————————————————————————10.13晚更新补充一下一面说的一些奇怪的概念:1,提到了RPC2,提到了fu(第四声)拷贝,我当时说我只知道零拷贝,知道mmap,然后他说mmap是其中的一种方式,然后他问我知不知道DPDK,我说不知道,他说这个是一个高性能的拷贝方式3,MMU这个前面加了一个什么字母我这里没记,别问我了4,后面还提到了LTU,VFIO,孩子真的不会。
走呀走:华子二面可能会有场景题的,是有些开放性的问题了
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务