Vectores C ++ STL: ¿Obtener iterador del índice?


201

Entonces, escribí un montón de código que accede a elementos en un vector stl por índice [], pero ahora necesito copiar solo una parte del vector. Parece que vector.insert(pos, first, last)es la función que quiero ... excepto que solo tengo primero y último como ints. ¿Hay alguna forma agradable de obtener un iterador para estos valores?



Si no me equivoco, ninguna de las respuestas verifica los límites, lo que podría ser un problema. Específicamente, los documentos std :: advance dicen que el comportamiento no está definido si lo usa para superar los límites del contenedor subyacente.
Martin Pecka

Respuestas:


293

Prueba esto:

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

44
En general, puede usar la misma aritmética con iteradores STL que con punteros. Están diseñados para ser intercambiables cuando se utilizan algoritmos STL.
Vincent Robert

18
@ VincentRobert: Al revés. Los punteros son implementaciones válidas de iteradores aleatorios STL, la categoría más poderosa. Pero otras categorías menos potentes, como los iteradores hacia adelante, no admiten la misma aritmética.
MSalters

66
Quisiera agregar mis cinco centavos a esta respuesta y recomendarstd::next(v.begin(), index)
stryku

88

manera mencionada por @dirkgently ( v.begin() + index )agradable y rápido para vectores

pero la forma más genérica y para los iteradores de acceso aleatorio también funciona a tiempo constante. std::advance( v.begin(), index )

EDITAR
diferencias en el uso:

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

o

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

agregado después de las notas @litb.


¿no requiere std :: advance un iterador no constante como primer argumento?
goldPseudo

puede utilizar std :: adelantado con const y no const iteradores
bayda

1
no debe confiar en msvc en ese sentido. tiene una extensión no estándar que lo hace aceptar este tipo de cosas, sin embargo, todos los demás compiladores se comportan de manera estándar y lo rechazan.
Johannes Schaub - litb

1
Creo que el problema es la confusión sobre el significado de "const": advance () funcionará felizmente en un const_iterator <T>, que es un iterador mutable que se refiere a un elemento const de tipo T; no funcionará en un objeto iterador que sea en sí mismo const (es decir, "const iterator <T>" o "iterator <T> const").
j_random_hacker

77
Si sabe que está tratando con un std::vector, no tiene sentido usarlo std::advance. Solo lo induce a pensar que está escribiendo código agnóstico de contenedor (que no lo hace, pensando en reglas de invalidación de iterador, diferentes complejidades de tiempo de ejecución y otras cosas). El único caso cuando std::advancetiene sentido es cuando escribe una plantilla usted mismo que no sabe con qué tipo de iterador está tratando.
Frerich Raabe

47

También; auto it = std::next(v.begin(), index);

Actualización: necesita un compilador compatible con C ++ 11x


2
Cabe señalar que esta es la forma C ++ 11! std :: next es equivalente a std :: advance. El uso de estas funciones en lugar de usar la aritmética facilita mucho el intercambio de tipos de contenedores. Incluso funciona en c-arrays afaik, al igual que std :: begin y std :: end.
Zoomulator

2
También debe tenerse en cuenta que std :: advance está diseñado por un idiota, ya que utiliza una referencia como salida, y no el valor de retorno.
Viktor Sehr

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

2
Ambos tienen sus usos. stda :: advance es útil para alterar el iterador en su lugar. Es una preocupación de rendimiento en bucles. Preferiría el siguiente en el caso de la asignación, como sugiere. Me pareció un poco duro decir que es idiota. Ambas funciones fueron diseñadas con diferentes situaciones en mente, a pesar de que son básicamente las mismas.
Zoomulator

55
@Zoomulator: si copiar su iterador es un problema de rendimiento, tiene problemas más importantes con los que lidiar.
Mooing Duck el


-3

Actualmente std :: vector están destinados a ser utilizados como pestaña C cuando sea necesario. (El estándar C ++ solicita que para la implementación de vectores, que yo sepa, reemplazo de la matriz en Wikipedia ) Por ejemplo, es perfectamente legal hacer lo siguiente, según yo:

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

Por supuesto, foo no debe copiar la dirección pasada como parámetro y almacenarla en algún lugar, o debe asegurarse en su programa de no insertar nunca ningún elemento nuevo en vec o solicitar cambiar su capacidad. O falla de segmentación de riesgo ...

Por lo tanto, en su ejemplo conduce a

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

Me hace preguntarme por qué decidieron abstraerse de los iteradores si solo son punteros ... esencialmente están "ocultando" estas capacidades.
mpen

Para consitencia? Como le permitiría eliminar fácilmente la instancia de vector para cualquier otro tipo de contenedor en su código, así.
yves Baumes

44
& vec [i] produce un puntero que no es necesariamente compatible con el vector <> :: iterador. vec.begin () + i todavía tiene la ventaja de ser el iterador que su biblioteca define, incluidos los iteradores marcados en modo de depuración, por ejemplo. Por lo tanto, si no necesita un puntero (por ejemplo, para E / S), siempre debe preferir iteradores.
sellibitze

@KerrekSB De 23.3.6.1 en el borrador estándar de c ++: "Los elementos de un vector se almacenan contiguamente, lo que significa que si v es un vector <T, Allocator> donde T es un tipo distinto de bool, entonces obedece a la identidad & v [ n] == & v [0] + n para todos 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes: eso no tiene nada que ver con los iteradores de vectores. Sin embargo, es cierto que los punteros desnudos también son iteradores, simplemente no son iteradores vectoriales .
Kerrek SB
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.