Modismo para hacer algo dos veces en C++
Frecuentes
Visto 810 veces
5
¿Existe un modismo común para hacer algo dos veces, como en la siguiente situación?
for ( int i = 0; i < num_pairs; i++ ) {
cards.push_back( Card(i) );
cards.push_back( Card(i) );
}
Tengo la sensación de que hay una manera más clara que la introducción de una nueva variable de ciclo que cuenta de 0 a 1, especialmente porque no se usa excepto para contar.
for ( int i = 0; i < num_pairs; i++ )
for ( int j = 0; j < 2; j++ )
cards.push_back( Card(i) );
(Card
es solo una clase que inventé y no es relevante para la pregunta).
5 Respuestas
10
Probablemente quieras usar el fill_n
Funcionar en <algorithm>
for ( int i = 0; i < num_pairs; i++ )
std::fill_n(std::back_inserter(cards), 2, Card(i));
contestado el 22 de mayo de 12 a las 20:05
6
Personalmente, lo dejaría como está. Se ve limpio, es fácil de entender y es bastante legible. Solo deja un comentario mencionando por qué lo haces dos veces (pero lo harías sin importar qué).
contestado el 22 de mayo de 12 a las 20:05
5
Tengo algunas sugerencias. Ver el pasado por mi recomendación:
en mi opinión
insert(it,
N
, value)
latidosstd::fill_n
:for ( int i = 0; i < num_pairs; i++ ) { cards.insert(cards.end(), 2, Card(i) ); }
Si el orden no es importante, puede generar las tarjetas una vez y duplicarlas. después de el hecho
std::copy(cards.begin(), cards.end(), std::back_inserter(cards));
Usando un truco sucio de lambda y división de enteros. advertencia esto tiene el sello de una optimización prematura: reduce la legibilidad sin una buena razón.
std::vector<Card> cards(num_pairs * 2); int i = 0; std::generate_n(cards.begin(), num_pairs, [&i] () { return Card(i++/2); });
(asume
Card
is construible por defecto. Si no, usacards.back_inserter()
)Mi recomendación
Lo siguiente gana tanto en desempeño como en expresión de intención:
std::vector<Card> cards; cards.reserve(num_pairs*2); for (int i = 0; i < num_pairs; ++i) { cards.emplace_back(i); cards.emplace_back(i); }
contestado el 22 de mayo de 12 a las 22:05
1
Tiene razón al usar la expansión del bucle interno en declaraciones, ya que usar otro bucle solo 2 iteraciones será malo para el rendimiento. Debido a los frecuentes jumps
, el segundo (bucles anidados) se ejecutará lentamente. Si habrá alguna diferencia notable depende completamente de la num_pairs
.
Entonces, el primero es mejor para el rendimiento (por marginal que sea la ganancia). Este tipo de bucles en expansión se llama loop unwinding/unrolling
en la terminología del compilador. Sin embargo, este término no se usa a nivel de programación, ya que generalmente solo el compilador lo hace para hacer que el código sea más rápido. Idioms
están seguros design notions
que ayudan a los programadores a escribir un código mejor y más eficiente y a entender mejor el lenguaje.
contestado el 22 de mayo de 12 a las 20:05
1
Si desea hacer esto con mucha frecuencia, escriba una pequeña función de utilidad:
template<class F>
void repeat(unsigned times, F callback) {
while (times--) callback();
}
// ...
for (int i = 0; i < num_pairs; i++) {
repeat(2, [&] { cards.push_back(Card(i)); });
}
Escribí un ejemplo en ideone.
Su primer enfoque puede resultar confuso para los futuros lectores de su código. Podrían pensar que el código estuvo allí dos veces por accidente. El uso de una función como esta evita esta confusión.
El impacto en el rendimiento sería muy mínimo, incluso > 0, ya que es probable que el compilador alinee la función y optimice completamente el ciclo para pequeños times
'. Si le preocupa el rendimiento, primero haga una evaluación comparativa.
contestado el 22 de mayo de 12 a las 21:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c++ idioms or haz tu propia pregunta.
¿A qué te refieres exactamente con idioma? ¿Qué tipo de respuesta estás buscando? - user1203803
legibilidad y mantenibilidad del valor - jglouie
No veo nada malo con el primer ejemplo. Los modismos son útiles para cosas más complejas y están destinados a hacer que los programas sean más comprensibles y correctos. Lo que estás preguntando es algo bastante sencillo, no es necesario que haya un modismo para ello. - Paul Manta
Si tuviera un vector o algo así, le recomendaría que lo use
std::for_each(start, end, []() {cards.push_back(Card(i));});
- LéoTu puedes decir
for (int dummy : { 0, 1 }) { /* do stuff */ }
. - Kerrek SB