Skip to content

Last updated:2026-10-12

STL array source code analysis

0.Introduction

The source code analysis is based on gcc4.9.1.

C++ tr1, fully named Technical Report 1, is the first extension to the C++ standard library. The C++ standard c++0x would include it, along with some extensions to the language itself. tr1 includes the long-awaited smart pointers, regular expressions, and other content supporting generic programming. During the draft stage, the namespace for the newly added classes and templates was std::tr1.

1.std::tr1::array

Usage:

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

The array in tr1 is fairly simple: it mimics the language's built-in arrays and makes them support iterator operations, so that like other containers it can be used with algorithms. In tr1, array has no constructor or destructor. The iterator is simply a pointer defined using the passed-in type.

Let's take a quick look at the source code of this static 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;
}
It uses reverse_iterator as the iterator for the rbegin and rend operations. It looks like there is one iterator above, but there are actually two; there is also another iterator, which simply uses a pointer defined via the passed-in type as the iterator.

You can think of it as the counterpart of the forward and reverse iterators in vector.

It is worth noting that tr1::array supports passing an array size of 0, for example:

std::tr1::array<int,0> a;
For this kind of writing, it maps to the following:
// Support for zero-sized arrays mandatory.
value_type _M_instance[_Nm ? _Nm : 1];
Based on the passed-in size: if it is not 0, it is the passed-in size; otherwise it is 1.

2.std::array

Usage

std::array<int ,10> a;

The array in std contains

std_array.png

Comparing the arrays of tr1 and 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;
}

We find two notable places inside 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;

Searching for __array_traits in the source code, we see:

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]); }
};

The two lines of code above can be understood as the following:

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

In actual code, if we want to define an array, we can write:

int a[100];
//或者
typedef int T[100];
typedef T a;
Compared with tr1, the handling of the passed-in size is more complex: template partial specialization is used to handle the case where the passed size is 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); }
};

Comments