Vetores C ++ STL: obtém o iterador do índice?


200

Então, escrevi um monte de código que acessa elementos em um vetor stl pelo index [], mas agora eu preciso copiar apenas uma parte do vetor. Parece que vector.insert(pos, first, last)é a função que eu quero ... exceto que eu tenho apenas o primeiro e o último como ints. Existe alguma maneira legal de obter um iterador para esses valores?



Se não estou errado, nenhuma das respostas faz nenhuma verificação de limites, o que pode ser um problema. Especificamente, os documentos std :: advance dizem que o comportamento é indefinido se você o usar para ultrapassar os limites do contêiner subjacente.
Martin Pecka

Respostas:


293

Tente o seguinte:

vector<Type>::iterator nth = v.begin() + index;

4
Geralmente, você pode usar a mesma aritmética com iteradores STL do que com ponteiros. Eles são projetados para serem intercambiáveis ​​ao usar algoritmos STL.
Vincent Robert

18
@VincentRobert: Ao contrário. Ponteiros são implementações válidas de iteradores aleatórios STL, a categoria mais poderosa. Mas outras categorias menos poderosas, como iteradores avançados, não suportam a mesma aritmética.
MSalters

6
Eu quero ot adicionar meus cinco centavos para esta resposta e recomendarstd::next(v.begin(), index)
stryku

87

maneira mencionada por @dirkgently ( v.begin() + index )agradável e rápido para vetores

mas a maneira mais genérica e os iteradores de acesso aleatório também funcionam em tempo constante. std::advance( v.begin(), index )

EDIT
diferenças no uso:

std::vector<>::iterator it = ( v.begin() + index );

ou

std::vector<>::iterator it = v.begin();
std::advance( it, index );

adicionado após as notas do @litb.


O std :: advance não exige um iterador não-const como o primeiro argumento?
goldPseudo

você pode usar std :: antecedência com const e não-const iterators
bayda

1
você não deve confiar no msvc a esse respeito. possui uma extensão não-padrão que o faz aceitar esse tipo de coisa; no entanto, todos os outros compiladores se comportam como padrão e o recusam.
Johannes Schaub - litb 22/03/09

1
Eu acho que o problema é a confusão sobre o significado de "const": advance () funcionará alegremente em um const_iterator <T>, que é um iterador mutável que se refere a um elemento const do tipo T; ele não funcionará em um objeto iterador que seja ele próprio const (ou seja, "const iterator <T>" ou "iterator <T> const").
j_random_hacker

7
Se você sabe que está lidando com um std::vector, não faz sentido usá-lo std::advance. Isso apenas o leva a pensar que está escrevendo código independente de contêiner (o que você não faz, pensando em regras de invalidação do iterador, diferentes complexidades de tempo de execução e outros enfeites). O único caso em que std::advancefaz sentido é quando você mesmo escreve um modelo que não sabe com que tipo de iterador está lidando.
Frerich Raabe 12/08

47

Além disso; auto it = std::next(v.begin(), index);

Atualização: Precisa de um compilador compatível com C ++ 11x


2
Note-se que esta é a maneira C ++ 11! std :: next é equivalente a std :: advance. O uso dessas funções em vez da aritmética facilita a troca de tipos de contêineres. Até funciona em c-arrays afaik, assim como std :: begin e std :: end.
Zoomulator

2
Deve-se notar também que std :: advance é projetado por um idiota, pois usa uma referência como saída, e não o valor de retorno.
Viktor Sehr

1
for (auto it = begin (c); it! = end (c); advance (it, n)) {...}
#

2
Ambos têm seus usos. stda :: advance é útil para alterar o iterador no local. É uma preocupação de desempenho em loops. Eu preferiria o próximo no caso de atribuição, como você sugere. Achei um pouco duro afirmar que era idiota. Ambas as funções foram projetadas com diferentes situações em mente, embora sejam basicamente as mesmas.
Zoomulator

5
@ Zoomulator: Se a cópia do seu iterador é uma preocupação de desempenho, você tem problemas maiores para resolver.
Mooing Duck


-3

Na verdade, std :: vector deve ser usado como guia C quando necessário. (O padrão C ++ solicita isso para implementação de vetores, tanto quanto eu sei - substituindo o array na Wikipedia ). Por exemplo, é perfeitamente legal fazer isso a seguir, de acordo com mim:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

Obviamente, o foo não deve copiar o endereço passado como parâmetro e armazená-lo em algum lugar, ou você deve garantir em seu programa que nunca forneça nenhum item novo no vec ou solicite a alteração de sua capacidade. Ou falha na segmentação de risco ...

Portanto, no seu exemplo, isso leva a

vector.insert(pos, &vec[first_index], &vec[last_index]);

Me faz pensar por que eles decidiram abstrair para os iteradores se eles são apenas indicadores ... eles estão basicamente "escondendo" esses recursos.
MPEN

Por consitência? Como isso permitiria remover facilmente a instância de vetor para qualquer outro tipo de contêiner no seu código.
yves Baumes

4
& vec [i] produz um ponteiro que não é necessariamente compatível com o vetor <> :: iterator. O vec.begin () + ainda tem o benefício de ser o iterador que sua biblioteca define - incluindo iteradores verificados no modo de depuração, por exemplo. Portanto, se você não precisa de um ponteiro (para E / S, por exemplo), sempre deve preferir iteradores.
sellibitze 27/09/09

@KerrekSB A partir de 23.3.6.1 no rascunho padrão do c ++: "Os elementos de um vetor são armazenados de forma contígua, o que significa que se v for um vetor <T, Alocator> em que T é algum tipo diferente de bool, ele obedece à identidade & v [ n] == & v [0] + n para todos os 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes: isso não tem nada a ver com iteradores de vetor. No entanto, é verdade que ponteiros nus também são iteradores - eles não são apenas vetores iteradores de .
21412 Kerrek SB
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.