2009-06-29 20 views
50

¿Alguien puede decirme cómo incrementar el iterador en 2?¿Cómo incrementar un iterador en 2?

iter++ está disponible - ¿Tengo que hacer iter+2? ¿Cómo puedo conseguir esto?

+4

A juzgar por la variedad de respuestas, puede que tenga que aclarar tu pregunta. – teabot

+0

Sí. ¿Qué tipo de iterador es? Muestra un código –

Respuesta

7

podría utilizar el 'asignación por adición' operador

iter += 2; 
+0

Me preguntaba si ++ iter ++ funcionaría, pero creo que sería confuso. – Xetius

+1

¿Qué pasará si el iterador señala actualmente el último elemento? ¿Dónde apuntará después del incremento? – sharptooth

+3

@Xetius: No deberías hacerlo. Es un comportamiento indefinido. – Naveen

80

std::advance(iter, 2);

Este método funcionará para iteradores que no son iteradores de acceso aleatorio, pero todavía se puede especializar por la aplicación para ser no menos eficiente que iter += 2 cuando se usa con iteradores de acceso aleatorio.

+0

¿Qué pasará si el iterador señala actualmente el último elemento? ¿Dónde apuntará después del incremento? Intenté con VC++, simplemente avanza y la comparación contra vector :: end() devuelve falso después de eso. Esta es una forma directa de comportamiento indefinido, supongo. – sharptooth

+1

Sí, si va a hacer std :: advance con '2', o + = 2, o dos '++' sin verificar si está 'end' en el medio, entonces necesita una garantía externa de que está no va a ir más allá de uno pasado el final. (Por ejemplo, puede * saber * que está iterando a través de los elementos pares (de base cero) de una colección que garantiza tener un número par de elementos). –

+0

cuál es la diferencia entre el siguiente (iter, 2) y el siguiente (iter, 2) – m1350

18

http://www.cplusplus.com/reference/std/iterator/advance/

std::advance(it,n); 

donde n es 2, en su caso.

La belleza de esta función es que si "él" es un iterador de acceso aleatorio, el ayuno

it += n 

operación se utiliza (es decir, el vector < ,,> :: iterador). Por lo demás es prestado a

for(int i = 0; i < n; i++) 
    ++it; 

(es decir, la lista < ..> :: iterador)

-5

La respuesta muy simple:

++++iter 

La respuesta larga:

que realmente debería tener utilizado para escribir ++iter en lugar de iter++. Este último debe devolver (una copia de) el valor anterior, que es diferente del nuevo valor; esto toma tiempo y espacio.

Tenga en cuenta que el incremento de prefijo (++iter) toma un valor l y devuelve un valor l, mientras que el incremento postfix (iter++) toma un valor l y devuelve un valor r.

+5

Comportamiento indefinido si 'iter' es un puntero sin formato (que pueden ser algunos tipos de iteradores). '++ it; ++ it; 'estaría bien. –

+0

Mala idea y no es muy legible. –

+1

Por favor, dime que esta no es una respuesta seria. – Axle

4

Si no sabe si tiene suficientes elementos siguientes en su contenedor o no, debe comprobar contra el final de su contenedor entre cada incremento. Ni ++ ni std :: advance lo harán por usted.

if(++iter == collection.end()) 
    ... // stop 

if(++iter == collection.end()) 
    ... // stop 

Incluso puede hacer rodar su propia función de avance seguro encuadernado.

Si está seguro de que no pasará del final, entonces std :: advance (iter, 2) es la mejor solución.

8

Si no tiene un lvalue modificable de un iterador, o si desea obtener una copia de un iterador dado (dejando el original sin modificar), entonces C++ 11 viene con nuevas funciones auxiliares - std::next/std::prev:

std::next(iter, 2);   // returns a copy of iter incremented by 2 
std::next(std::begin(v), 2); // returns a copy of begin(v) incremented by 2 
std::prev(iter, 2);   // returns a copy of iter decremented by 2 
+0

Si tengo un iterador como este: 'map :: iterator iter; for (iter = variations.begin(); iter! = Variations.end(); iter ++) { map :: iterador it_tmp = std :: next (iter, 1); // incremento en 1 it_tmp = std :: next (iter, 2); // incremento por 2 } ' ¿** Iter ** se incrementará en 2? o * iter * solo afectará it_tmp? –

+0

@HaniGoc Only it_tmp – metamorphosis

1

podemos utilizar tanto adelantado, así como el próximo. Pero, hay una diferencia entre los dos. "avance" modifica su argumento y no devuelve nada.Por lo tanto, se puede utilizar como:

vector<int> v; 
v.push_back(1); 
v.push_back(2); 
auto itr = v.begin(); 
advance(itr, 1);   //modifies the itr 
cout << *itr<<endl  //prints 2 

"siguiente" devuelve una copia modificada del iterador

vector<int> v; 
v.push_back(1); 
v.push_back(2); 
cout << *next(v.begin(), 1) << endl; //prints 2 
0

Suponiendo tamaño de la lista puede no ser un múltiplo par del paso que debe protegerse de desbordamiento:

static constexpr auto step = 2; 

// Guard against invalid initial iterator. 
if (!list.empty()) 
{ 
    for (auto it = list.begin(); /*nothing here*/; std::advance(it, step)) 
    { 
     // do stuff... 

     // Guard against advance past end of iterator. 
     if (std::distance(it, list.end()) > step) 
      break; 
    } 
} 

Dependiendo de la implementación de la recopilación, el cálculo de la distancia puede ser muy lento. A continuación es óptimo y más legible. El cierre se podría cambiar a una plantilla de servicio con el valor de la lista final pasada por referencia const:

const auto advance = [&](list_type::iterator& it, size_t step) 
{ 
    for (size_t i = 0; it != list.end() && i < step; std::next(it), ++i); 
}; 

static constexpr auto step = 2; 

for (auto it = list.begin(); it != list.end(); advance(it, step)) 
{ 
    // do stuff... 
} 

Si no hay un bucle:

static constexpr auto step = 2; 
auto it = list.begin(); 

if (step <= list.size()) 
{ 
    std::advance(it, step); 
} 
Cuestiones relacionadas