2012-08-13 12 views
8

Los iteradores que satisfacen los requisitos de los iteradores de salida se denominan iteradores variables. Los iteradores no mutables se denominan iteradores constantes . [24.2.1: 4]¿El incremento de un iterador de entrada mutable invalida los valores del iterador anterior?

Esto sugiere que podría tener un iterador de entrada mutable, que cumpla con los requisitos de los iteradores de entrada y salida.

Después de incrementar un iterador de entrada, las copias de su valor anterior no necesitan ser desmarcables [24.2.3]. Sin embargo, el estándar no dice lo mismo para los iteradores de salida; de hecho, la semántica operacional para el incremento de postfix se da como { X tmp = r; ++r; return tmp; }, lo que sugiere que los iteradores de salida no pueden invalidar (copias de) los valores del iterador anterior.

Entonces, ¿el incremento de un iterador de entrada mutable invalida las copias antiguas del iterador?

En caso afirmativo, ¿cómo podría admitir código como X a(r++); *a = t o X::reference p(*r++); p = t con (por ejemplo) un objeto proxy?

Si no es así, ¿por qué boost::iterator dice que necesita un objeto proxy? (El enlace es código; desplácese hacia abajo para leer los comentarios en struct s writable_postfix_increment_proxy y postfix_increment_result). Es decir, si puede devolver una copia (sin referencia) del antiguo valor del iterador, ¿por qué debería envolver esta copia en un proxy?

+0

Oh, cómo detesto estas preguntas de abogado de idiomas. También podría discutir sobre cuántos ángeles bailan en la cabeza de un alfiler. –

+4

@MarkRansom Sí, detesto cuando las personas intentan entender el lenguaje que están usando. Malditos sean todos ... Y necesito decirle al mundo sobre mi odio por ellos aquí en * este * comentario (para el registro, las categorías de iteradores son una gran cosa en C++. Comprender qué puede hacer cada uno de ellos es bastante útil) – jalf

+0

@MarkRansom: Mi pregunta es importante para mí porque una respuesta afirmativa significa que tengo que agregar otro objeto proxy a mi clase para manejar los iteradores de entrada mutables, como lo hace Boost. El consenso a continuación sugiere que no existe un iterador de entrada mutable (a pesar del comentario en 24.2.1: 4). Esto, a su vez, sugiere que Boost es incorrecto en el manejo de "iteradores de entrada mutables", incluso si los desarrolladores de Boost entendieron mal este aspecto del estándar, ¿no es un problema que debería abordarse? – nknight

Respuesta

6

La explicación si se encuentra en la siguiente sección, [24.2.5] iteradores Delantero, donde se afirma cómo éstos difieren de entrada y de salida iteradores:

Dos iteradores Dereferenceable a y b de tipo X oferta la garantía de pasos múltiples si:

- a == b implica ++a == ++b y
- X es un tipo de puntero o la expresión (void)++X(a), *a es equivalente a la expresión *a. [Nota: el requisito a == b implica ++a == ++b (que no es verdadero para los iteradores de entrada y salida) y la eliminación de las restricciones en el número de asignaciones a través de un iterador mutable (que se aplica a iteradores de salida) permite el uso de algoritmos multidireccionales unidireccionales con iteradores directos. -fin nota]

Por desgracia, la norma debe leerse como un todo, y la explicación no es siempre donde se espera que sea.

+0

Todavía estoy confundido, lo siento. ¿Está diciendo que para que un iterador de entrada mutable no invalide valores antiguos, debe cumplir la garantía de múltiples pasadas? ¡Agradezco tu respuesta! – nknight

+2

No, estoy diciendo que se requiere un iterador directo para hacer lo que desea, un iterador de entrada no. El estándar no tiene nada en el medio. Incluso si tiene * algunos * de los atributos de un iterador directo, sigue siendo un iterador de entrada o salida hasta que se cumplan los requisitos * todos *. Considere que un iterador de entrada podría estar conectado a un teclado. Incluso si guarda una copia, no puede hacer una copia de seguridad y que vuelva a escribir el texto. Similar para un iterador de salida, podría ir directamente a una impresora. –

+2

¡Oh! Guardaré esa analogía de teclado/impresora para su futura reutilización: D –

4

Los iteradores de entrada y salida están diseñados básicamente para permitir el recorrido transversal de un solo paso: para describir secuencias donde cada elemento solo se puede visitar una vez.

Las transmisiones son un gran ejemplo. Si lee desde stdin o un socket, o escribe en un archivo, entonces solo está la posición actual de la ruta. Todos los demás iteradores que apuntan a la misma secuencia subyacente se invalidan cuando incrementa un iterador.

iteradores hacia adelante, deje de múltiples pasadas de recorrido, la garantía adicional que necesita: aseguran que se puede copiar su iterador, incrementar el original y la copia se todavía punto a la antigua posición, por lo que pueden recorrer desde allí .

+0

"* Todos los demás iteradores que apuntan a la misma secuencia subyacente se invalidan cuando se incrementa un iterador. *" --- de hecho esta es la intención del estándar (para los iteradores tanto de entrada como de salida), aunque C++ 11 no lo hace Esto lo hace explícito para los iteradores de salida, ya que esta corrección: (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2035) no entró en la versión publicada (ver http://stackoverflow.com/a/11938988/985943 para más detalles). – nknight

Cuestiones relacionadas