std::array为11标准中带来的可以替代C风格数组的聚合类型,可以通过聚合初始化生成"C++风格"上的"C风格"数组:
1
| std::array<int, 3> a = {1, 2, 3};
|
主要代码如下:
std::array主要代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| template<typename _Tp, size_t _Nm> struct __array_traits {
using _Type = _Tp[_Nm]; using _Is_swappable = __is_swappable<_Tp>; using _Is_nothrow_swappable = __is_nothrow_swappable<_Tp>; };
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;
typename __array_traits<_Tp, _Nm>::_Type _M_elems; }
|
可以看到std::array<_Tp, _Nm> 这个template struct在_Nm不为零时实际为_Tp[_Nm]的wrapper, iterator为_Tp*,公开数据成员、没有虚基类和虚成员函数、没有定义构造函数使array成为聚合类型,可使用聚合初始化,而实际占用内存与对应C风格数组一致。
array<T,0>特化
上文提到_Nm类型参数不为零时,是由于array相比C风格数组拥有可为空集合的特性,在arrary<T,0>时其内部__array_traits拥有特化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| template<typename _Tp> struct __array_traits<_Tp, 0> { struct _Type { __attribute__((__always_inline__,__noreturn__)) _Tp& operator[](size_t) const noexcept { __builtin_trap(); }
__attribute__((__always_inline__)) constexpr explicit operator _Tp*() const noexcept { return nullptr; } };
using _Is_swappable = true_type; using _Is_nothrow_swappable = true_type; };
|
也就是__array_traits<_Tp, 0>实际不拥有数据成员,为空类型使array<T,0>占1字节,两个成员operator接口看着有点迷糊,我们可以来看看array的一些成员方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| [[__gnu__::__const__, __nodiscard__]] _GLIBCXX17_CONSTEXPR iterator begin() noexcept { return iterator(data()); }
[[__nodiscard__]] _GLIBCXX17_CONSTEXPR reference operator[](size_type __n) noexcept { __glibcxx_requires_subscript(__n); return _M_elems[__n]; }
[[__nodiscard__, __gnu__::__const__, __gnu__::__always_inline__]] _GLIBCXX17_CONSTEXPR pointer data() noexcept { return static_cast<pointer>(_M_elems); }
|
可以看到data方法是将实际_Tp[_Nm] static_cast为"_Tp*"后返回,operator[]则实际返回_Tp[_Nm]这个C风格数组的指定下标。这则是__array_traits<_Tp, 0>的operator[]和operator _Tp*()的用处,在调用诸如array<int,0>对象的operator[]时直接程序崩溃,调用其data()方法时返回nullptr。