En el código de ejemplo, a menudo veo código como *it++
para los iteradores de salida. La expresión *it++
realiza una copia de it
, incrementa it
y luego devuelve la copia que finalmente se desreferencia. Según lo entiendo, hacer una copia de un iterador de salida invalida la fuente. Pero entonces el incremento de it
que se realiza después de crear la copia sería ilegal, ¿verdad? ¿Está mi comprensión de los iteradores de salida defectuosa?¿Cómo es * it ++ válido para los iteradores de salida?
Respuesta
La expresión hace *it++
no (tienen que) hacer una copia del mismo, hace no incrementarlo, etc. Esta expresión es válida sólo por conveniencia, ya que sigue la semántica usual. Solo operator=
hace el trabajo real. Por ejemplo, en la implementación de g ++ de ostream_iterator
, operator*
, operator++
y operator++(int)
haga solo una cosa: return *this
(en otras palabras, ¡nada!).Podríamos escribir por ejemplo:
it = 1;
it = 2;
*it = 3;
++it = 4;
En lugar de: *it++ = 1; *it++ = 2; *it++ = 3; *it++ = 4;
Esta es la respuesta que me dio un momento aha, por lo tanto, la estoy seleccionando como la correcta. – fredoverflow
Probablemente debería dejar en claro que el primer ejemplo solo funciona porque conoce la implementación y el segundo ejemplo es la forma correcta de usar un iterador de salida. – Dingo
@Dingo: si entiendo correctamente el estándar, no depende de la implementación sino que está bien definido para 'ostream_iterator'. Entonces, en el caso general no se puede requerir que '* it ++' haga una copia, etc. – rafak
¿No es un iterador solo un puntero? Incrementando, luego desreferenciando simplemente pasa al siguiente elemento.
No, los iteradores no son solo punteros. –
Se pueden desreferenciar, al igual que un puntero, esto puede generar confusión, pero no, no son solo punteros, sino que apuntan a un elemento, entre otras cosas. Aquí hay una implementación de muestra de un iterador: http://www.accu-usa.org/Listings/2000-04-Listing01.html –
Ah, ya veo. Nunca he visto el punto en los iteradores, y nunca los he necesitado. –
Los iteradores de salida simplemente no funcionan como iteradores normales y su interfaz se especifica para que puedan usarse en expresiones tipo puntero (*it++ = x
) con resultados útiles.
Típicamente, operator*()
, operator++()
y operator++(int)
todo volver *this
como referencia y los iteradores de salida tienen una magia operator=
que lleva a cabo la operación de salida esperada. Como no se puede leer desde un iterador de salida, no importa el hecho de queetc., no funcione como para otros iteradores.
El estándar requiere que *r++ = t
funcione para los iteradores de salida (24.1.2). Si no funciona, no es un iterador de salida según la definición del estándar.
Depende de la implementación del iterador asegurarse de que tales declaraciones funcionen correctamente bajo el capó.
La razón por la que no debe conservar varias copias de un iterador de salida es que tiene una semántica de pase único. El iterador solo puede desreferenciarse una vez en cada valor (es decir, debe incrementarse entre cada operación de desreferencia). Una vez que se elimina la referencia de un iterador, no se puede copiar.
Es por eso que *r++ = t
funciona. Se realiza una copia del iterador original, se elimina la referencia del iterador original y se incrementa la copia. El iterador original nunca volverá a utilizarse y la copia ya no hará referencia al mismo valor.
Mirando tu comentario, parece que la mayor parte de la confusión surge de la documentación de SGI, que diría que es un poco engañosa en este punto.
Copiar un iterador de salida no no invalidar el iterador copiado. La verdadera limitación es bastante simple: solo debe desreferenciar un valor determinado del iterador de salida una vez. Sin embargo, tener dos copias a la vez está bien, siempre y cuando solo elimines una de ellas mientras tienen el mismo valor. En un caso como en el que está desreferenciando uno, luego descartando su valor e incrementando el otro, pero solo desreferenciando una vez que se ha producido el incremento, todo está perfectamente bien.
- 1. Aumente los iteradores de Property_Tree, cómo manejarlos?
- 2. ¿List-it() es seguro para subprocesos?
- 3. ¿Cómo escribir un buscapersonas para los iteradores de Python?
- 4. Cómo utilizar los dominios internacionales de Internet (.it, .co.uk, .es, ...) a lo mejor para SEO
- 5. ¿Cuál es la diferencia entre los iteradores de entrada y los iteradores de solo lectura hacia adelante?
- 6. Cómo aplanar los iteradores de contenedores anidados?
- 7. ¿La precedencia del operador en C++ difiere para los punteros y los iteradores?
- 8. Suprime la salida "val it" en el estándar ML
- 9. Incrementando iteradores: ¿es más eficiente que él ++?
- 10. Uso correcto de los bloques iteradores
- 11. Longitud de los datos para descifrar es válido
- 12. devolver iteradores de C++
- 13. ¿Cómo se hacen los iteradores anidados en Groovy?
- 14. PHP Elimina recursivamente los directorios vacíos con los iteradores SPL
- 15. vector iteradores de reparto
- 16. ¿Hasta qué punto es "boost does it" equivalente a "very portable, use it"?
- 17. ¿Alguien puede explicar el enfoque "Fake it till you it it" en Test Driven Development?
- 18. ¿Es válido para definir funciones en los resultados JSON?
- 19. ¿Es válido comparar iteradores que se obtienen del contenedor por separado?
- 20. Error de compilación utilizando los iteradores de mapa
- 21. ¿Es correcto recorrer QMap con iteradores y borrar/agregar elementos?
- 22. ++ it or it ++ cuando se itera sobre un mapa?
- 23. ¿Cambiar el tamaño de un vector invalida los iteradores?
- 24. rspec "it" cadena
- 25. ¿Los contenedores que pasan por valor invalidan los iteradores?
- 26. W3Schools Editor Try-it
- 27. ¿Cuál es la convención normal para nombrar y usar iteradores en C++?
- 28. es una cadena de consulta con a/in it valid?
- 29. alias 'it' en rspec
- 30. ¿Cómo uso los iteradores anidados con Mustache.js o Handlebars.js?
¿Por qué la copia de un iterador (salida o de otra manera) invalidarla? No rutinariamente hacemos esto cuando decimos cosas como: 'vector :: iterator it (container.begin());' –
@Adrian: Por ejemplo, la [documentación de SGI] (http: //www.sgi. com/tech/stl/OutputIterator.html) dice: "Solo debe haber una copia activa de un solo Iterator de salida en un momento dado. Es decir: después de crear y usar una copia x de un Iterator de salida y, el iterador de salida original y ya no se debe usar ". Sin embargo, no estoy seguro de qué significa "usar" un iterador de salida en este contexto. ¿Desreferencia? Incrementando? – fredoverflow
Veo la implicación de que después de 'out_iterator a (b);', 'b' podría no ser válido en la documentación de SGI como usted dijo, pero nada en C++ 03 lo insinúa. Pero como tanto la página SGI como C++ 03 dicen explícitamente que la expresión '* it ++ = value' debe ser válida, ese requisito anula cualquier otra preocupación sobre ese uso. – aschepler