Ir para o conteúdo

Última atualização:2026-10-12

Análise do código-fonte do STL array

0. Introdução

A análise do código-fonte usa a versão gcc 4.9.1.

C++ tr1, cujo nome completo é Technical Report 1, é a primeira extensão da biblioteca padrão de C++. O padrão de C++ c++0x viria a incluí-la, junto com alguns acréscimos à própria linguagem. O tr1 inclui o há muito esperado smart pointer, expressões regulares e outros recursos de apoio à programação genérica. Na fase de rascunho, o namespace das novas classes e templates era std::tr1.

1. std::tr1::array

Uso:

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

O array do tr1 é relativamente simples: simula um array da própria linguagem e o faz suportar operações com iteradores, para que, assim como os demais contêineres, possa chamar algoritmos. No array do tr1 não há construtor nem destrutor. O iterador é simplesmente um ponteiro definido a partir do tipo passado.

Vamos dar uma olhada rápida no código-fonte deste array estático:

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 dele usa-se reverse_iterator como iterador das operações rbegin e rend. Parece haver apenas um iterador acima, mas na verdade são dois: há também um iterator, que usa diretamente um ponteiro definido com o tipo passado, servindo como iterador.

Pode-se fazer um paralelo com os iteradores direto e reverso do vector.

Vale a pena notar que, em tr1::array, é permitido passar tamanho de array igual a 0; por exemplo, podemos usar o seguinte:

std::tr1::array<int,0> a;
Para uma escrita como essa, corresponde o trecho abaixo:
// Support for zero-sized arrays mandatory.
value_type _M_instance[_Nm ? _Nm : 1];
De acordo com o tamanho passado: se não for 0, é o próprio tamanho passado; caso contrário, 1.

2. std::array

Uso

std::array<int ,10> a;

O array do std inclui

std_array.png

Comparando o array do tr1 com o do 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;
}

Percebe-se que há dois pontos dignos de atenção no 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;

Procurando __array_traits no código-fonte, encontramos:

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

As duas linhas de código acima podem ser entendidas como o seguinte:

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

Na prática, ao escrever código, se quisermos definir um array, podemos escrever assim:

int a[100];
//或者
typedef int T[100];
typedef T a;
Em comparação com o tr1, o tratamento do tamanho passado é mais sofisticado, usando especialização parcial de template para tratar o caso em que o tamanho passado é 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); }
};

Tópicos relacionados

Comentários