2010-09-09 9 views
14

¿es posible buscar el siguiente elemento en un contenedor al que apunta el iterador sin cambiar el iterador?Examinar el siguiente elemento en el contenedor STL

Por ejemplo, en std :: set,

int myArray[]= {1,2,3,4}; 
set <int> mySet(myArray, myArray+4); 
set <int>::iterator iter = mySet.begin(); 

//peek the next element in set without changing iterator. 

mySet.erase(iter); //erase the element if next element is n+1 
+3

¿Por qué no hacer una copia y adelantar que uno? ¡Asegúrate de verificar si cualquiera de los iteradores es igual a '.end()' antes de continuar! – GManNickG

+0

Creo que estaba confundiendo el iterador con un puntero. cuando asigna un puntero a un puntero, ambos cambiarán si un puntero cambia pero ¿por qué no ocurre en el caso de un iterador? – user963241

+0

@GMan: Boost tiene las funciones 'prior' y' next' para hacer justamente eso (toma el iterador por valor, haciendo una copia como sugeriste). Ver http://www.boost.org/libs/utility/utility.htm para más detalles. –

Respuesta

13

No con iteradores en general. No se garantiza que un iterador pueda operar de forma no destructiva. El ejemplo clásico es un Iterador de entrada que realmente representa un flujo de entrada subyacente.

Sin embargo, hay algo que funciona para este tipo de iterador. Un Forward Iterator no invalida copias anteriores de sí mismo por el hecho de avanzar en la colección. La mayoría de los iteradores (incluidos aquellos para colecciones STL) son al menos Reenviar iteradores, si no una versión más funcional, solo Iteradores de entrada o Iteradores de salida son más restringidos. De modo que puede simplemente hacer una copia de su iterador, incrementar la copia y marcar que, luego volver a su iterador original.

Así que su código vistazo:

set <int>::iterator dupe = iter; 
++dupe; 
// (do stuff with dupe) 
3
set <int>::iterator iter2 = iter; 
++iter2; 
int peekedValue = *iter2; 
0

Siempre se puede hacer una copia del iterador y avanzar en la copia:

set <int>::iterator iter = mySet.begin(); 
set <int>::iterator iterCopy = iter; 
iterCopy++; 
if (*iterCopy == something) 
    mySet.erase(iter); 

Pero ten en cuenta que ya no puede iterCopy sea ​​válido una vez que borre iter.

+0

"iterCopy puede dejar de ser válido una vez que lo borre". Será para un conjunto, pero no para todos los contenedores STL. Busco "SGI STL set" o lo que sea cuando quiero una buena referencia ... cubre todo esto. –

+0

Tenga en cuenta, sin embargo, que SGI es un gran recurso para el STL. Sin embargo, no es del todo exacto en cuanto a la biblioteca estándar de C++. El STL contiene varios contenedores/algoritmos no estándar, y los contenedores que son parte del estándar C++ no coinciden con algunos de los detalles, particularmente con respecto a los asignadores. –

0

para contenedores de secuencias (vector, deque, y la lista) se puede llamar frontal que le dará un vistazo (más información en la parte inferior de esta link).

0

Esto no funcionará para std::set como su naturaleza no permite que el operador [], pero para los contenedores que hacer, se puede hacer:

std::vector<int> v; 
v.push_back(3); 
v.push_back(4); 
std::vector<int>::iterator it = v.begin(); 
std::cout << v[it - v.begin() + 1]; 

Pero esto podría ser peligroso si it puntos a la última elemento en el contenedor; pero lo mismo se aplica a la solución anterior. P.ej. Tendrás que hacer cheques en ambos casos.

+0

¿Por qué usar 'operator []' cuando ya tienes un iterador? Si quiere lo que 'it' actualmente señala, use' * it'. Si quiere lo que el iterador señala después de 'it', use algo como' * (it + 1) 'o' std :: vector :: iterator it2 (it); std :: advance (it2, 1); * it2; '. Por cierto, el código presentado solo funcionará para un' std :: vector' (por ejemplo, no funcionará con un 'std :: deque'). –

24

C++ 0x agrega una práctica función de utilidad, std::next, que copia un iterador, lo avanza y devuelve el iterador avanzado. Usted puede escribir su propia aplicación std::next:

#include <iterator> 

template <typename ForwardIt> 
ForwardIt next(ForwardIt it, 
       typename std::iterator_traits<ForwardIt>::difference_type n = 1) 
{ 
    std::advance(it, n); 
    return it; 
} 

puede utilizar esto en su ejemplo, así:

if (iter != mySet.end() && next(iter) != mySet.end() && *next(iter) == *iter + 1) 
    mySet.erase(iter); 
+3

+1, no sabía que fue adoptado. Por cierto, '++ move (iter)' hace lo mismo. – Potatoswatter

+0

No soy un experto con plantillas, así que me tomó un tiempo asimilar completamente este pequeño código y casi fui con la solución más sencilla provista por @AndrewShephard. Pero en el último minuto se dio cuenta de que esta solución es funcionalmente la misma (pero no idéntica) al código fuente 4.4.x y 4.9.x de gcc ubicado en '/ usr/include/C++/$ {gcc_version}/bits/stl_iterator_base_funcs.h' y entonces fui con esta solución. –

+0

Veo http://en.cppreference.com/w/cpp/iterator/next dice que es desde C++ 11, ¿cuál es el correcto? – zhangxaochen

Cuestiones relacionadas