2011-06-21 20 views
15

I actualmente tiene el siguiente bucle for:Iterador de segundo al último elemento de una lista

for(list<string>::iterator jt=it->begin(); jt!=it->end()-1; jt++) 

I tiene una lista de cadenas que está en una lista más grande (list<list<string> >). Quiero recorrer el contenido de la lista interna hasta que llegue al segundo elemento. Esto se debe a que ya procesé los contenidos del elemento final y no tengo motivos para procesarlos nuevamente.

Sin embargo, el uso de it->end()-1 no es válido. No puedo usar el operador - aquí. Si bien podría usar el operador --, esto disminuiría este iterador final en cada ciclo.

Creo que una lista STL es una lista doblemente vinculada, por lo que desde mi punto de vista, debería ser posible hacerlo.

¿Asesoramiento? Gracias de antemano

Respuesta

9

recomendación Requisitos para utilizar la biblioteca estándar:

std::for_each(lst.begin(), --lst.end(), process); 

Si no quiere complicarse con la creación de un funtor [Casi nunca hago], y no se puede utilizar iteradores inversa, izar la comprobación final del bucle:

for(iterator i = lst.begin(), j = --lst.end(); i != j; ++i) { 
    // do 
    // stuff 
} 

O, que sólo puede confiar en que el optimizador de reconocer que no tiene que mantener a recrear la condición final, y hacer el izado en sí. Cuán confiable es esto depende de la implementación de la lista y de la complejidad del código de bucle y de lo bueno que sea su optimizador.

En cualquier caso, solo haga lo que le resulte más fácil de entender y preocúpese por el rendimiento una vez que haya terminado.

+0

Aprecié la simplicidad de esta solución. Sí, otras soluciones con un iterador inverso fueron agradables, pero tu solución me enseñó un método sin usar un iterador especial. – BSchlinker

+0

"Si no quieres complicarte creando un functor", hoy te recomendaría simplemente poner una lambda allí – Paladin

6

El iterador de lista no es un iterador aleatorio. Usted debe hacer lo siguiente:

if (! it->empty()) 
{ 
    list<string>::iterator test = it->end(); 
    --test; 
    for(list<string>::iterator jt = it->begin(); jt != test; ++jt) 
    { 
    ... 
    } 
} 

Una cosa más: utilizar ++jt contra jt++. jt++ código fuente por lo general se ve algo como esto:

iterator operator++ (int i) 
{ 
    iterator temp = (*this); 
    ++(*this); 
    return temp; 
}; 
4

Mientras que podría utilizar el operador -, esto podría disminuir este iterador final sobre cada ciclo.

No, no lo haría. Obtendría una copia del iterador final y la disminuirá. Eso es todo. No cambiaría el iterador final almacenado en la lista.

Su problema principal debe ser verificar que la lista es no vacía, lo que garantiza que --it-> end() existe.

4

¿qué tal un iterador inverso?

for(list<string>::reverse_iterator jt=++(it->rbegin()); jt!=it->rend(); jt++) 
+0

En realidad, esto se traduce en un error debido a la utilización de la "!" operador en la declaración "jt! = it-> rend();" – BSchlinker

+0

El tipo debe ser 'list :: reverse_iterator' en lugar de simplemente' list :: iterator'. –

+0

No estaba al tanto de los iteradores inversos, ¡gracias! – BSchlinker

1

en C++ 11 y más tarde, la mejor respuesta parece ser el uso de std::prev

for(iterator i = lst.begin(); i != std::prev(lst.end()); ++i) { 
    // do 
    // stuff 
} 

La documentación para std :: anterior en http://en.cppreference.com/w/cpp/iterator/prev dice,

Aunque la expresión - c.end() a menudo compila, no se garantiza que lo haga: c.end() es una expresión rvalue, y no hay requisito de iterador que especifique que se garantiza que el decremento de un valor r funcione. En particular, cuando los iteradores se implementan como punteros, --c.end() no se compila, mientras que std :: prev (c.end()) sí lo hace.

Creo std :: prev() en una lista vacía no está definido, por lo que puede que tenga que terminar con esto en una condición !i.empty()

Cuestiones relacionadas