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++ 语言基础
