Share via


Iterators

Um iterador é um objeto que pode iterar em elementos em um contêiner da Biblioteca Padrão do C++ e fornecer acesso a elementos individuais. Os contêineres da Biblioteca Padrão do C++ fornecem iteradores de modo que todos os algoritmos possam acessar seus elementos de maneira padrão sem precisar se preocupar com o tipo do contêiner em que os elementos estão armazenados.

Você pode usar iteradores explicitamente usando funções de membro e globais, como begin() e end(), e operadores, como ++ e --, para avançar ou retroceder. Também é possível usar iteradores implicitamente com um loop range-for ou (para alguns tipos de iterador) o operador subscrito [].

Na Biblioteca Padrão do C++, o início de uma sequência ou intervalo é o primeiro elemento. O final de uma sequência ou intervalo sempre é definido como um após o último elemento. As funções globais begin e end retornam iteradores para um contêiner especificado. O loop do iterador explícito típico sobre todos os elementos em um contêiner tem esta aparência:

vector<int> vec{ 0,1,2,3,4 };
for (auto it = begin(vec); it != end(vec); it++)
{
    // Access element using dereference operator
    cout << *it << " ";
}

A mesma coisa pode ser feita de forma mais simples com um intervalo range-for:

for (auto num : vec)
{
    // no dereference operator
    cout << num << " ";
}

Há cinco categorias de iteradores. Em ordem crescente de potência, as categorias são:

  • Saída. Um iterador de saídaX pode iterar para frente em uma sequência usando o operador ++, e pode gravar um elemento apenas uma vez, usando o operador *.

  • Entrada. Um iterador de entradaX pode iterar para frente em uma sequência usando o operador ++, e pode ler um elemento quantas vezes forem necessárias usando o operador *. É possível comparar iteradores de entrada usando os operadores == e !=. Depois de você incrementar qualquer cópia de um iterador de entrada, nenhuma das outras cópias poderá ser comparada, cancelada ou incrementada com segurança.

  • Encaminhar. Um iterador de avançoX pode iterar para frente em uma sequência usando o operador ++, e pode ler qualquer elemento ou gravar elementos não constantes quantas vezes forem necessárias usando o operador *. É possível acessar os membros do elemento usando o operador -> e comparar iteradores de avanço usando os operadores == e !=. Você pode fazer várias cópias de um iterador de avanço, cada uma das quais pode ser desreferenciada e incrementada de forma independente. Um iterador de avanço inicializado sem referência a nenhum contêiner é chamado de iterador de avanço nulo. Iteradores de avanço nulos sempre são comparados como iguais.

  • Bidirecional. Um iterador bidirecionalX pode tomar o lugar de um iterador de avanço. Você também pode, no entanto, decrementar um iterador bidirecional, como em --X, X-- ou (V = *X--). É possível acessar membros do elemento e comparar iteradores bidirecionais da mesma forma que ocorre com iteradores de avanço.

  • Acesso aleatório. Um iterador de acesso aleatórioX pode tomar o lugar de um iterador bidirecional. Com um iterador de acesso aleatório, você pode usar o operador subscrito [] para acessar elementos. É possível usar os operadores +, -, += e -= para avançar ou retroceder um número especificado de elementos e para calcular a distância entre iteradores. Você pode comparar iteradores bidirecionais usando ==, !=, <, >, <= e >=.

Todos os iteradores podem ser atribuídos ou copiados. Eles são considerados objetos leves e geralmente são passados e retornados por valor, não por referência. Observe também que nenhuma das operações descritas anteriormente pode gerar uma exceção quando executada em um iterador válido.

A hierarquia das categorias de iterador pode ser resumida mostrando três sequências. Para acesso somente gravação a uma sequência, você pode usar qualquer um entre:

iterador de saída
-> iterador de avanço
-> iterador bidirecional
-> iterador de acesso aleatório

A seta direita significa "pode ser substituído por". Qualquer algoritmo que chama um iterador de saída deve funcionar bem com um iterador de avanço, por exemplo, mas não o oposto.

Para acesso somente leitura a uma sequência, você pode usar qualquer um entre:

iterador de entrada
-> iterador de avanço
-> iterador bidirecional
-> iterador de acesso aleatório

Um iterador de entrada é a mais fraca de todas as categorias, nesse caso.

Por fim, para acesso de leitura/gravação a uma sequência, você pode usar qualquer um entre:

iterador de avanço
-> iterador bidirecional
-> iterador de acesso aleatório

Um ponteiro de objeto sempre pode servir como um iterador de acesso aleatório, de modo que ele pode servir como qualquer categoria de iterador se der suporte para o acesso de leitura/gravação adequado para a sequência que designa.

Um iterador Iterator diferente de um ponteiro de objeto também deve definir os tipos de membro exigidos pela especialização iterator_traits<Iterator>. Esses requisitos podem ser atendidos derivando Iterator do iterador da classe base pública.

É importante compreender as promessas e limitações de cada categoria de iterador para ver como os iteradores são usados por contêineres e algoritmos na Biblioteca Padrão do C++.

Observação

É possível evitar o uso de iteradores explicitamente usando loops range-for. Para obter mais informações, consulte Instrução baseada em intervalo.

O Microsoft C++ agora oferece iteradores verificados e iteradores de depuração para garantir que você não substitua os limites de seu contêiner. Para obter mais informações, consulte Iteradores verificados e Suporte para iterador de depuração.

Confira também

Referência da biblioteca padrão C++
Acesso Thread-Safe na Biblioteca Padrão C++