2010-09-29 10 views
6

Siento que no soy profesional en la forma en que elijo y uso los iteradores. Lo que quiero decir con eso es que "siento" que debería llamarlos de otra manera, pero siempre los nombro basándose en el prefijo "it_", y después de un tiempo, en una función larga, todos los nombres se parecen a todos .¿Cuál es la convención normal para nombrar y usar iteradores en C++?

Además, siempre me pregunto si estoy haciendo las cosas de una manera "extraña" que aprendí solo porque no lo sabía. Por ejemplo, si estuviera iteración a través de un mapa para mostrar todos sus pares clave/valor, me gustaría hacer esto:

 
map<int, int>::const_iterator it = layout.begin(); 
for (; it != layout.end(); ++it) 
{ 
   cout << it->first << ":\t" << it->second << "\n"; 
}

Veo algunas personas llamando a sus iteradores "iter" - Veo otras formas de hacer bucles. ¿Hay algún tipo de convención que trascienda el estilo y que sea solo una buena práctica?

+0

casi todas mis variables de bucle se llaman 'loop' (a menos que haya una doble anidación). –

+0

@Martin: mis iteradores usualmente son 'it' y' end' ... pero luego usan 'BOOST_FOREACH' constantemente, no los saco a menudo. –

+0

A, maneras de intentar y reemplazar un bucle con un algoritmo. No es un fan BOOST_FOREACH debido al nombre de mayúsculas (hace que el código parezca feo). –

Respuesta

4

trato de declarar los iteradores en el interior del for en bucle tanto como sea posible, de modo que el alcance del identificador del iterador se minimiza.

En primer lugar, typedef los nombres de tipo "largo" a "cortas" y reutilizables queridos:

typedef std::map< int, int > IntMap; 
typedef IntMap::const_iterator IntMapConstIter; 

Entonces, hago

for(IntMapConstIter it = layout.begin(); it != layout.end(); ++it) { 
    .... 
} 
+1

Ni siquiera lo había considerado, y una de las cosas que me preocupaba * era * alcance. ¿Cómo lidiar con las declaraciones "para" increíblemente largas que tienden a resultar? Lo mejor que puedo pensar es hacer un typedef para el tipo de datos para acortarlo. – Tim

+0

Solo arrójelo, vea mi respuesta. Me resulta más legible que declarar una variable fuera del ciclo. –

+0

Personalmente escribo el tipo de datos, luego separa el enunciado para en 3 piezas en 3 líneas diferentes. –

0

El nombre es lo menos importante para mí, siempre y cuando esté claro y elegido adecuadamente.

Esto cae en el debate sin fin de variables nombrar

  • m_ para los miembros
  • de arrastre para resaltar los miembros
  • etc ...
2

lo hago de la siguiente manera

for (map<int, int>::const_iterator it = layout.begin(); 
    it != layout.end(); ++it) 
{ 
    cout << it->first << ":\t" << it->second << "\n"; 
} 

Gracias a eso, el iterador tiene un alcance solo dentro del bloque, lo que lo hace más seguro para darle un n más corto ame

+0

¡Genial! Vi a ArunSaha dar la misma respuesta antes, y todo este tiempo ni siquiera había pensado en romper el ciclo "para" en varias líneas para tratar con la longitud. ¡Gracias! – Tim

+0

De nada, a veces la solución más simple es la más difícil de notar. –

2

Estoy bastante seguro de que ninguna convención trasciende el estilo en este asunto. Creo que la parte más importante de la denominación de iteradores está en la segunda parte (considerando que decides agregar un prefijo, si es "it" o "iter_" o cualquier otra cosa). Elija la segunda parte cuidadosamente como lo haría con cualquier otra variable y estará bien.

1

¿Sería totalmente irracional para mí sugerir el uso de BOOST_FOREACH y para que (sobre todo) olvide los iteradores?

+0

No, en absoluto, simplemente no he usado Boost aún, aunque sé en general todas las cosas geniales que ofrece – Tim

+0

No he usado el foreach de boost (he usado implementaciones específicas de proyectos).Aún así, pensar en el nivel de iterador es bueno cuando se está insertando o eliminando durante la iteración, rastreando varios iteradores al mismo tiempo, etc. ¿No creo que boost foreach ofrece algo para esas circunstancias ...? –

+0

@Tony: no hace más que modificar la estructura subyacente del contenedor mientras se itera sobre él ... es complicado hacerlo bien. Prefiero usar 'algorithm' para la tarea O usar una estructura de datos temporal alternativa que cambiaré con la actual al final del ciclo. –

1

No he visto un solo bucle canónico.

El costo de crear un iterator se especifica como O(1) (del tamaño del contenedor), pero puede costar, especialmente cuando se activan las opciones de depuración específicas.

Por lo tanto, llamar al end en cada iteración del ciclo es un desperdicio.

La forma canónica de escribir un bucle for es, por lo tanto, calcular it y end en la primera instrucción.

typedef std::map<int,int> LayoutType; 

for (LayoutType::const_iterator it = layout.begin(), end = layout.end(); 
    it != end; ++it) 
{ 
    // ... 
} 

lo general typedef mi contenedor, pero la verdad es que no tiene mucho sentido typedefing el iterador, que ya está disponible dentro del contenedor y la introducción de demasiados sinónimos no ayuda.

Además, puede ser un capricho personal, pero yo prefiero que indica la funciónen lugar de la tipo cuando me presente a mi typedef. El tipo puede cambiar en la refactorización posterior, la función no (al menos, no será lo mismo si lo hace, por lo que requerirá una reescritura completa).

Por ejemplo, ¿qué pasa si de repente prefiere: typedef std::unordered_map<int,int> LayoutType? Todavía coincide con su necesidad, y probablemente pueda colocarlo sin costo de reescritura (siempre que haya usado un typedef).

+0

+1 para muchos puntos buenos, aunque creo que todo el problema de precomputación final es demasiado exagerado; solo circunstancias extremas o un diseño deficiente dan como resultado un final lento() ;-). Además, algunas operaciones feas pueden cambiar end() durante la iteración: bastante desagradable por sí mismo, pero peor aún con un valor de caché end(). En resumen, no es gran cosa, diría yo. –

+0

@Tony: nunca dije que fuera la única forma, pero creo que es la canónica. Aunque este bucle se reemplaza ventajosamente por 'BOOST_FOREACH' o el nuevo * rango por * expresión de C++ 0x que oculta cuidadosamente las cosas del iterador. –

+0

Sí, estaba tratando de notar mi desacuerdo sobre esa afirmación "canónica": en todo caso diría 'para (Iterator i = x.find/begin /?(); I! = X.end(); ++ i) 'era canónico, para bien o para mal (después de todo, canónico no significa la mejor práctica). Es un alivio que auto, range, foreach, etc. estén en camino. –

Cuestiones relacionadas