librerias - ¿Los iteradores de C++ se consideran dañinos?
manual completo de c++ pdf (13)
Andrei Alexandrescu , autor del libro Modern C ++ Design y Loki C ++ library, dio una charla titulada "Iterators Must Go" ( video , slides ) acerca de por qué los iteradores son malos y tuvo una mejor solución.
Intenté leer las diapositivas de presentación, pero no pude sacar mucho de ellas.
- ¿Son malos los iteradores?
- ¿Su reemplazo es realmente mejor?
- ¿Los implementadores de C ++ recogerán sus ideas?
- Algunas veces
- Probablemente
- No es probable, al menos no por muchos años.
- La mayoría de nosotros hacemos un uso simple de ellos en lo que se ha convertido en expresiones idiomáticas bien conocidas, como en los bucles for para recorrer un std :: vector. Un desarrollador lo lee y sabe lo que está pasando. En nuestra vida diaria de codificación, los iteradores no son buenos ni malos, son simplemente "lo que hace el trabajo".
- Probablemente si.
- No lo creo.
No, no son malos, son idea muy inteligente de hecho. Sin embargo, no son ideales y hay espacio para mejoras en el concepto de iterador.
Resuelve el número de problemas de la vida real con iteradores. Por ejemplo, es tedioso (también propenso a errores) en muchos casos consultar dos objetos separados, iteradores, desde un solo contenedor y luego pasarlos como dos objetos separados a un algoritmo. ¿Por qué no pasar un solo objeto? Incluso
std::pair<iterator, iterator>
generaría un rango simple que es más fácil de manipular: un objeto, no dos. Además, es una buena idea considerar quea range is an iterator
. De hecho, eso es lo que sugiere Andrei. Por cierto, algunos de estos problemas ya han sido resueltos por Boost.Range .Yo esperaría que sucediera, pero no será una revolución, sino una evolución.
¿Andrei no está tratando de hacer algo de marketing oculto para el lenguaje D (actualmente está trabajando con él) ...?
Andrei afirma que los contenedores están bien, pero los iteradores son feos, no intuitivos, propensos a errores y peligrosos, difíciles de implementar (bueno, este último parece ser bastante cierto ...) ¿Y qué tenemos en C ++ ... punteros? ? ¿No son feos /.../ peligrosos? Pero felizmente los abrazamos y vivimos con ellos.
Cuál es más intuitivo de escribir:
for(auto i=foo.begin();i!=foo.end();++i)
bar(*i);
o
for (auto r=foo.all(); !foo.empty(); foo.popFront())
bar(r.front());
El concepto de iteradores puede complementarse con rangos y otras ideas, pero creo que tienen su lugar y no serán reemplazados.
Al igual que cualquier API o función, si se usa incorrectamente puede crear muchos problemas de identificación difíciles. Los iteradores se han utilizado en muchos proyectos, pero siempre manteniendo el cuidado necesario requerido de acuerdo a sus características. Su uso debe estar precedido por una buena comprensión de sus limitaciones. Los iteradores pueden ser muy útiles si el usuario lo hace correctamente.
Estas preguntas están relacionadas:
¿Hay alguna forma de verificar si un iterador es válido?
¿Debo preferir iteradores a const_iterators?
Andrei a veces puede ser un poco provocativo. Los iteradores son un concepto razonable y bastante fundamental en el sentido de que los bits son. Pero al igual que la mayoría de los bits en C ++ no son bools, sino que forman parte de los tipos más grandes, la mayoría de los iteradores deben tratarse a un nivel alto. Andrei tiene razón en que el nivel adecuado para hacerlo es el objeto de rango. Pero no todos los rangos están adecuadamente expuestos como rangos de iteradores, como lo muestra el centinela istream_iterator. Eso es sólo un truco para crear un iterador final artificial. Sin embargo, no creo que sus ideas sean recogidas por implementaciones. C ++ 1x será tan relevante como C99.
C ++ 0x ya está haciendo los primeros pasos:
- Las referencias de valores solucionan algunos problemas con el tratamiento de contenedores como rangos.
- Los rangos se han agregado a la biblioteca principal, incluidos los conceptos de rango.
La transición a rangos sin perder ninguna funcionalidad de iterador (piense en todas las combinaciones de categorías de iteradores, constancia y valor-valor) es difícil, especialmente si intenta tener en cuenta los rangos infinitos y mutables.
Creo que deberíamos usar rangos junto a los iteradores, es decir, deberíamos elegir el modo de evolución, no el de revolución.
Creo que los implementadores de C ++ tendrán las manos llenas produciendo soporte completo de trabajo para C ++ 0x, sin implementar nuevos paradigmas no estándar.
El único argumento que puedo ver en esa presentación es la incapacidad de definir rangos, y la propuesta de c ++ 0x "Rango para declaración" parece eliminar ese problema en cierta medida de todos modos. tal vez no debería ser un argumento sobre si los iteradores deberían / no deberían usarse en absoluto, pero más ¿para qué situaciones deberían / no deberían usarse?
Estoy de acuerdo con él en que los iteradores son en su mayoría inferiores a los rangos, y no sé si "algo mejor" será recogido.
"Lo bueno es el enemigo de lo mejor" está fuertemente en juego aquí, como suele serlo. Los iteradores son útiles y están firmemente arraigados, por lo que es difícil saber si algo mejor como los rangos puede suplantarlos en un tiempo razonable.
No estoy de acuerdo con Andrei y Konrad y conmigo :-)
El concepto más fundamental es una interfaz, no un iterador, y eso es bastante obvio en cualquier trabajo que alguien haga hoy (que se trata de bibliotecas cruzadas, lenguajes cruzados, compiladores cruzados, sistemas operativos cruzados, plataformas cruzadas, nombres cruzados) eso :-)
Ni el iterador ni el rango (aparte del uso a nivel de fuente) ofrecen algo más que un simple y no intrusivo o intrusivo, no compartido o compartido, no único o único: ¡puntero! El puntero limpio a los datos escritos es simplemente universal y puede hacer que los datos sean mutables o inmutables y muchas otras cosas. Toda la interfaz es solo otro nivel de direccionamiento indirecto al mismo tiempo que sigue siendo amigable con la máquina y el compilador de todo tipo, además de mucho más seguro, relegando los iteradores y el uso del rango a un detalle de implementación.
Hasta ese punto, IEnumerable e IQueryable hacen la mitad ''cosa correcta'' TM pero son claramente inferiores en sus conceptos de iteración y mucho más de lo que puede hacer con STL, retener el control y así sucesivamente (pero otoh, tienen mejores metadatos y de ahí un modelo mejor y más limpio). En cuanto a las interfaces, puede crear cualquier abstracción que desee y satisfacer, probablemente contraversiva, pero esencialmente una obviedad: representación y código de datos neutros en tiempo de compilación o óptimos (óptimo para los algoritmos y compiladores y máquinas virtuales). .
Incluso es posible optimizarlo para sistemas ''dinámicos'' / componentes hasta el ''tiempo de ejecución'' en línea (atornille HotSpot VM :-). En ese sentido, el avance a 1975 es mínimo como lo evidencia una enorme carga de trabajo de la industria de interoperabilidad (está en todas partes mira, incluido este sitio, su uso de tecnología patentada y abierta, etc .; en el idealismo de la informática, bueno, este tipo de "trabajo" de interfaz no debería existir si ...
Primero, para responder a tus preguntas:
- No. De hecho, argumenté en elsewhere que los iteradores son el concepto más importante / fundamental de la informática. Yo (a diferencia de Andrei) también creo que los iteradores son intuitivos .
- Sí, definitivamente, pero eso no debería ser una sorpresa.
- Hmm Mirando a Boost.Range y C ++ 0x, ¿no lo han hecho ya?
La gran contribución de Andrei aquí es solo para decir: elimine el concepto de iteradores en conjunto, vea los rangos no solo como un envoltorio de conveniencia sino como una construcción central. Otros lenguajes ya lo han hecho (muchos de los conceptos de Andrei simplemente se hacen eco de LINQ o los iteradores de Python de .NET) pero todos ellos solo ofrecen rangos de salida . Andrei defiende diferentes tipos de rangos, al igual que las categorías de iteradores convencionales.
En ese sentido, es extraño que comience burlándose de la arbitrariedad de estas categorías de iteradores.
También creo que sus ejemplos están desactivados, especialmente su copia de archivos: sí, la variante de iterador es una gran mejora con respecto al código de 1975. Reduce un bucle con una condición de interrupción complicada a una sola instrucción. Con lo que realmente está teniendo problemas aquí es solo la sintaxis. Bueno, discúlpeme: estamos hablando de C ++ aquí, por supuesto, la sintaxis es fea. Y sí, usar rangos aquí es una mejora, pero solo sintácticamente.
También creo que la implementación del find
de Andrei está desactivada. Lo que realmente define es la operación DropUntil
(¡nombrar es difícil!) De LINQ. La operación de find
realmente debería devolver uno o cero elementos (¡o un iterador!). En mi opinión, evitar los iteradores aquí no es útil, ya que es posible que desee modificar el valor directamente en lugar de copiarlo. Devolver un rango de un elemento aquí solo agrega gastos generales sin un beneficio. Hacerlo es incorrecto porque el nombre del método es incorrecto y confuso.
Dicho esto, estoy esencialmente de acuerdo con Andrei en casi todos los puntos. Los iteradores, aunque son mi concepto favorito de la informática, son sin duda una gran carga sintáctica y muchos rangos (especialmente generadores infinitos) pueden (y deben) implementarse convenientemente sin ellos.