Перейти к содержанию

Последнее обновление:2026-10-12

Анализ исходников STL array

0. Введение

Анализ исходников выполнен для версии gcc4.9.1.

C++ tr1, полное название Technical Report 1, — первое расширение стандартной библиотеки C++. Стандарт C++ c++0x должен был включить его, а также некоторые расширения самого языка. tr1 включает давно ожидаемые умные указатели, регулярные выражения и ряд других средств поддержки обобщённого программирования. На этапе черновика пространством имён новых классов и шаблонов было std::tr1.

1. std::tr1::array

Использование:

#include <tr1/array>
std::tr1::array<int ,10> a;

array в tr1 довольно прост: он имитирует встроенный в язык массив и наделяет его поддержкой итераторов, чтобы, как и другие контейнеры, его можно было использовать с алгоритмами. В array из tr1 нет конструктора и деструктора. Итератор — это просто указатель, определённый через переданный извне тип.

Взглянем кратко на исходники этого статического массива array:

template<typename _Tp, std::size_t _Nm>
struct array
{
    typedef _Tp                           value_type;
    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;
}
Внутри в качестве итератора для операций rbegin и rend используется reverse_iterator. Кажется, что итератор выше один, но на самом деле их два: есть ещё iterator — тоже просто указатель, определённый через переданный извне тип и используемый как итератор.

Это можно сопоставить с прямыми и обратными итераторами в vector.

Стоит отметить, что tr1::array поддерживает передачу нулевого размера массива, например:

std::tr1::array<int,0> a;
Такая запись соответствует следующему:
// Support for zero-sized arrays mandatory.
value_type _M_instance[_Nm ? _Nm : 1];
В зависимости от переданного размера: если он не 0 — берётся переданный размер, иначе — 1.

2. std::array

Использование

std::array<int ,10> a;

array из std включает

std_array.png

Сравним array из tr1 и из std

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 _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type;    // # define _GLIBCXX_STD_C std
    typename _AT_Type::_Type                         _M_elems;
}

В array можно отметить два момента:

// Support for zero-sized arrays mandatory.
typedef _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type;    // # define _GLIBCXX_STD_C std
typename _AT_Type::_Type                         _M_elems;

Поищем __array_traits в исходниках и увидим:

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

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

Две строки кода выше можно понять так:

typedef _Tp _Type[100];
typedef _Type _M_elems;  // 一个含有100个元素的数组。

При написании кода, если нужно определить массив, мы можем записать:

int a[100];
//或者
typedef int T[100];
typedef T a;
Обработка переданного размера здесь сложнее, чем в tr1: используется частичная специализация шаблона для случая размера 0.

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

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

template<typename _Tp>
struct __array_traits<_Tp, 0>
{
    struct _Type { };

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

Похожие темы

Комментарии