2010-01-03 12 views
31

Duplicar posible:
Why use iterators instead of array indices?¿Por qué usar string :: iterator en lugar de index?

string::iterator it; 
for (it = str.begin(); it < str.end(); it++) 
    cout << *it; 
cout << endl; 

Por qué no:

for (int i = 0; i < str.size(); i++) 
    cout << str[i]; 
cout << endl; 

Parece que la cadena :: iterador no proporciona prueba de alcance tampoco. ¿Por qué deberíamos usar string::iterator en lugar de índice?

Gracias.

+13

La pregunta es por qué ¿No usarías 'cout << str << endl;'. – avakar

+6

@jcyang: aparte de las respuestas de los demás, asegúrese de crear el hábito de usar preincremento con iteradores en bucles. es decir, usar ++ it y no lo ++. El pre-incremento no creará temporales temporales innecesarios. – Jagannath

+5

Además del comentario de Jagannath, prefiera 'operator! =()' Sobre 'operator <()' al comparar un iterador con 'end()'. – jason

Respuesta

22

El índice solo se puede usar para contenedores que admiten acceso aleatorio: acceso directo a una posición determinada.

El iterador ofrece una forma unificada para acceder a cualquier estructura de recopilación/datos. La flexibilidad al refacturar su código es inmensa.

-2

En C++, puede hacer muchas cosas de diferentes maneras. Este es un ejemplo más. En este caso, no hay diferencia qué método usar. Pero en general, los iteradores son más rápidos, más seguros y brindan más flexibilidad frente a diferentes tipos de contenedores.

0

Ambas obras.

La razón principal sería la coherencia: está iterando sobre una colección o los caracteres de una cadena de la misma manera, solicitando un iterador y avanzando.

No diría que los detalles de implementación de ++it que resultan en un incremento de puntero en comparación con str[i] que implican aritmética de puntero vale la pena mencionar. Y el control de rango también es un detalle de implementación.

1

Como se ha indicado in this question, método size() no se garantiza que sea O (1)

+1

No parece claro a partir de ese hilo. Un comentario menciona que 's.end() - s.begin()' definitivamente tiene una complejidad constante, por lo que uno tendría que estar loco para implementar size() con una complejidad peor. – UncleBens

+0

¿Por qué? El tamaño puede basarse en strlen() - similar que es O (stringLength). Para implementar size() en O (1), necesitará memoria ... – Drakosha

+2

s.size() no se puede implementar con strlen() - similar, ya que std :: string puede contener cualquier carácter (incluido ''\ 0''). Además, la cadena debe hacer un seguimiento de dónde termina (o su tamaño). ¿Por qué piensas que a continuación() y los iteradores serían mejores si la cadena no conociera su longitud y tuviese que encontrar el final en O (N)? – UncleBens

16

iteradores son una interfaz estándar. Al usar iteradores, puede usar los mismos algoritmos con diferentes contenedores. La decisión final de usarlos o no dependerá de usted en función de la facilidad de uso y la legibilidad.

Por ejemplo, usando el estándar transformar algoritmo para convertir std::string a mayúsculas:

std::string str = "A String"; 
std::transform(str.begin(), str.end(), str.begin(), ::toupper); 

resultará en str siendo igual a "A STRING".

+0

¿qué ocurre con la cadena específica :: iterator? ¿Hay algún beneficio, por ejemplo? – Jichao

+0

@jcyang: Solo eso si usa iteradores, entonces funciona donde se esperan los iteradores, y la cadena se puede cambiar a una matriz de caracteres o un vector u otro contenedor, y su ciclo seguirá funcionando. – jalf

+0

En el ejemplo anterior, el método 'std :: string :: begin()' devuelve un 'std :: string :: iterator', como con' std :: string :: end() '. El beneficio es que puede usar el algoritmo 'std :: transform'. No puedes usarlo con índices. –

0

iteradores son más seguros y proporcionar más flexibilidad como publicado por otra persona too.In additon un índice sólo se puede utilizar para recipientes de que el apoyo (eficiente) azar acceso (es decir, acceso directo a un elemento en una posición dada) . Un iterador es un concepto más general. Los iteradores ofrecen un recorrido eficiente de listas enlazadas, archivos y una cantidad de otras estructuras de datos. A menudo conduce a la generación de más eficiente código.

+4

Los iteradores no son más rápidos. todas las pruebas que se han hecho alguna vez al usarlas indican que son algo más lentas. –

+0

Gracias, he corregido mi publicación. –

1

En los casos en que no sabe qué clase está iterando (porque es un argumento de plantilla), debe usar un iterador porque no todas las clases que proporcionan un iterador también proporcionan [] (y no todas las clases que proporcionar [], proporciona uno que funciona en O (1) tiempo). Entonces, al usar el iterador, se asegurará de que la función funcione con tantas clases como sea posible (aunque no con matrices C).

En este caso específico, no veo ninguna razón para preferir uno sobre el otro, excepto las preferencias personales o tal vez una optimización prematura.

0

Supongo que una razón más por la que los iteradores deberían preferirse a los índices es que no todas las colecciones admiten el acceso aleatorio en tiempo constante.

Por ejemplo, si desea que el elemento -ésimo n en una lista enlazada, es necesario recorrer todos los elementos anteriores (con índices 0 .. n-1 ) hasta llegar a la n - th elemento. (Esta operación lleva tiempo lineal.)

Un iterador (secuencial) recuerda dónde se encuentra en una colección y no siempre tiene que volver a empezar desde el principio cuando desea el siguiente elemento. En su ejemplo, en realidad no necesita acceder a los caracteres de una cadena en orden aleatorio, sino solo de forma secuencial, por lo que el uso de un iterador seguramente será más rápido (tiempo constante).

2

Duplicado de:

  1. Iterators.. why use them?
  2. Why use iterators instead of array indices?

Dicho esto, es una cuestión de generalidad. Puede hacer un lote más con iteradores que usan STL que con acceso a matriz. Además, si necesita refactorizar el código y cambiar la cadena a un vector, list o rope, no tendrá que volver a escribir el código.

Finalmente está la cuestión de la seguridad en la iteración. Si desea acceder al carácter NEXT en su ciclo, con iteradores puede hacerlo de forma segura, pero aumentar el subíndice de matriz puede segfault sobre usted en el último elemento, por lo tanto, necesita otra verificación.

+2

Intentar acceder (desreferencia) al siguiente carácter en un bucle no es más seguro con iteradores que con subíndices de matriz. Ambos necesitan un control para asegurarte de que aún no estás al final de la cadena. –

5

Para std :: string específicamente, le sugiero que utilice índices, ya que es compatible con acceso aleatorio y es más simple. La única razón por la que se recomienda utilizar los iteradores es porque los iteradores ofrecen una interfaz estándar para acceder a las secuencias, de modo que si su secuencia cambiara a std :: list, su código de iteración no se vería afectado

+0

También tenga en cuenta que los iteradores pueden invalidarse, mientras que los índices no. – musiphil

Cuestiones relacionadas