Saltar a contenido

Última actualización:2026-10-12

Análisis del código fuente de STL array

0. Introducción

El análisis del código fuente se basa en la versión gcc4.9.1.

C++ tr1, cuyo nombre completo es Technical Report 1, es la primera extensión de la biblioteca estándar de C++. El estándar de C++ c++0x la incluiría, junto con algunas ampliaciones del propio lenguaje. tr1 incluye los tan esperados smart pointers, las expresiones regulares y otros contenidos que dan soporte a la programación genérica. En la etapa de borrador, el espacio de nombres de las nuevas clases y plantillas era std::tr1.

1.std::tr1::array

Uso:

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

El array de tr1 es relativamente sencillo: simula el array del propio lenguaje y lo dota de operaciones con iteradores, de modo que, igual que otros contenedores, puede invocar algoritmos. El array de tr1 no tiene constructor ni destructor. El iterador es simplemente un puntero definido directamente con el tipo que se pasa.

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;
}
Dentro se usa reverse_iterator como iterador de las operaciones rbegin y rend. A simple vista parece un solo iterador, pero en realidad son dos: además hay un iterator que usa directamente, como iterador, un puntero definido con el tipo que se pasa.

Se puede comparar con los iteradores directo y inverso de vector.

Cabe señalar que en tr1::array se permite pasar un tamaño de array de 0; por ejemplo, lo usamos así:

std::tr1::array<int,0> a;
Esta forma de escribirlo corresponde a lo siguiente:
// Support for zero-sized arrays mandatory.
value_type _M_instance[_Nm ? _Nm : 1];
Según el tamaño que se pase: si no es 0, es el tamaño pasado; si lo es, será 1.

2.std::array

Uso

std::array<int ,10> a;

El array de std incluye std_array.png

Comparación entre el array de tr1 y el de 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;
}

Se observan dos puntos destacables dentro de 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;

Buscando __array_traits en el código fuente, se ve:

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

Las dos líneas de código anteriores pueden entenderse como lo siguiente:

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

Al escribir código en la práctica, si queremos definir un array, podemos hacerlo así:

int a[100];
//或者
typedef int T[100];
typedef T a;
El tratamiento del size que se pasa, en comparación con tr1, es más complejo: se usa una especialización parcial de plantilla para gestionar el caso en que el size pasado es 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); }
};

Temas relacionados

Comentarios