while for ejemplos ciclo bucle for-loop language-agnostic loop-counter

for loop - ejemplos - ¿Debería esperar ver el contador en el bucle `for` cambiado dentro de su cuerpo?



ejemplos de do while en javascript (7)

Estoy leyendo el código de otra persona e incrementan por separado su contador de bucles for dentro del bucle, además de incluir el pensamiento posterior habitual. Por ejemplo:

for( int y = 4; y < 12; y++ ) { // blah if( var < othervar ) { y++; } // blah }

Basado en la mayoría del código que otros han escrito y leído, ¿debería esperar ver esto?


Así que después de cierta confusión, es decir, cerca, reapertura, actualización del cuerpo de la pregunta, actualización del título, creo que la pregunta es finalmente clara. Y también ya no se basa en la opinión.

Como lo entiendo la pregunta es:

Cuando miro el código escrito por otros, ¿debería esperar ver que se cambie la "variable de condición de bucle" en el cuerpo del bucle?

La respuesta a esto es una clara:

Cuando trabaje con otro código, independientemente de si realiza una revisión, corrige un error, agrega una nueva función, deberá esperar lo peor.

Todo lo que es válido dentro del idioma es de esperar.

No haga suposiciones acerca de que el código esté de acuerdo con ninguna buena práctica.


Es realmente mejor escribir como un bucle while

y = 4; while(y < 12) { /* body */ if(condition) y++; y++; }

A veces se puede separar la lógica de bucle del cuerpo.

while(y < 12) { /* body */ y += condition ? 2 : 1; }

Permitiría el método for () solo si raramente "omite" un elemento, como escapes en una cadena entre comillas.


La práctica de manipular el contador de bucle dentro de un bucle for no está exactamente extendida. Sorprendería a muchas de las personas que leen ese código. Y sorprender a tus lectores rara vez es una buena idea.

La manipulación adicional de su contador de bucles agrega una tonelada de complejidad a su código porque debe tener en cuenta lo que significa y cómo afecta el comportamiento general del bucle. Como mencionó Arkady, hace que su código sea mucho más difícil de mantener.

En pocas palabras, evita este patrón . Cuando sigue los principios de "código limpio", especialmente el principio de una sola capa de abstracción (SLA) , no existe tal cosa como

for(something) if (somethingElse) y++

Seguir el principio requiere que muevas ese bloque en su propio método, haciendo que sea difícil manipular algún contador externo dentro de ese método.

Pero más allá de eso, puede haber situaciones en las que "algo" como tu ejemplo crea; pero para esos casos, ¿por qué no usar un bucle while entonces?

En otras palabras: lo que hace que su ejemplo sea complicado y confuso es el hecho de que dos partes diferentes del código cambian su contador de bucles. Así que otro enfoque podría ser:

while (y < whatever) { ... y = determineY(y, who, knows); }

Ese nuevo método podría ser el lugar central para averiguar cómo actualizar la variable de bucle.


Para lo que vale, esto es lo que las Directrices principales de C ++ tienen que decir sobre el tema:

http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-loop-counter

ES.86: Evite modificar las variables de control de bucle dentro del cuerpo de los bucles for-raw sin formato 

Motivo El control de bucle por adelantado debe permitir un razonamiento correcto sobre lo que está sucediendo dentro del bucle. La modificación de los contadores de bucles tanto en la iteración-expresión como en el interior del cuerpo del bucle es una fuente perenne de sorpresas y errores.

También tenga en cuenta que en las otras respuestas aquí que tratan el caso con std::map , el incremento de la variable de control todavía se realiza solo una vez por iteración, donde en su ejemplo, se puede hacer más de una vez por iteración.


Pido discrepar con la aclamada respuesta anterior. No hay nada de malo en manipular la variable de control de bucle dentro del cuerpo del bucle. Por ejemplo, aquí está el ejemplo clásico de limpiar el mapa:

for (auto it = map.begin(), e = map.end(); it != e; ) { if (it->second == 10) it = map.erase(it); else ++it; }

Ya que he señalado con razón el hecho de que los iteradores no son lo mismo que una variable de control numérica, consideremos un ejemplo de análisis de la cadena. Supongamos que la cadena consta de una serie de caracteres, donde los caracteres con el prefijo ''/' se consideran especiales y deben omitirse:

for (size_t i = 0; i < s_len; ++i) { if (s[i] == ''//') { ++i; continue; } process_symbol(s[i]); }


Si incrementa dentro del bucle, asegúrese de comentarlo. Un ejemplo canónico (basado en un artículo de Scott Meyers Effective C ++) se encuentra en la sección de preguntas y respuestas ¿Cómo eliminar de un mapa mientras lo iteramos? (copia del código textual)

for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */) { if (must_delete) { m.erase(it++); // or "it = m.erase(it)" since C++11 } else { ++it; } }

Aquí, tanto la naturaleza no constante del iterador end() como el incremento dentro del bucle son sorprendentes, por lo que necesitan ser documentados. Nota: la elevación del bucle aquí es, después de todo, posible, por lo que probablemente debería hacerse para la claridad del código.


Utilice un bucle while en su lugar.

Si bien puedes hacer esto con un bucle for, no debes hacerlo. Recuerde que un programa es como cualquier otro elemento de comunicación, y debe hacerse teniendo en cuenta a su audiencia. Para un programa, la audiencia incluye el compilador y la siguiente persona para realizar el mantenimiento del código (probablemente en unos 6 meses).

Para el compilador, el código se toma muy literalmente: configure una variable de índice, ejecute el cuerpo del bucle, ejecute el incremento, luego verifique la condición para ver si está haciendo un ciclo nuevamente. Al compilador no le importa si haces mono con el índice de bucle.

Sin embargo, para una persona, un bucle for tiene un significado implícito específico: ejecutar este bucle un número fijo de veces . Si te monas con el índice de bucle, esto viola la implicación. En cierto sentido, es deshonesto y es importante porque la siguiente persona que lea el código tendrá que hacer un esfuerzo adicional para comprender el bucle o no lo hará y, por lo tanto, no podrá entenderlo.

Si desea simular con el índice de bucle, use un bucle while. Especialmente en C / C ++ / lenguajes relacionados, un bucle for es exactamente tan poderoso como un bucle while, por lo que nunca perderá ningún poder o expresividad. Cualquier bucle for se puede convertir en un bucle while y viceversa. Sin embargo, la siguiente persona que lo lea no dependerá de la implicación de que usted no es un mono con el índice de bucle. Hacer que sea un bucle while en lugar de un bucle for es una advertencia de que este tipo de bucle puede ser más complicado y, en su caso, de hecho es más complicado.