2009-04-09 7 views
6

Estoy usando una gran cantidad de código STL con std::for_each, bind, y así sucesivamente, pero me di cuenta de que a veces el uso de STL no es una buena idea.¿Cuánto de STL es demasiado?

Por ejemplo, si usted tiene un std::vector y quiere hacer una acción en cada elemento del vector, su primera idea es utilizar esto:

std::for_each(vec.begin(), vec.end(), Foo()) 

y es elegante y bien, por un tiempo. Pero luego viene el primer conjunto de informes de fallas y usted tiene que modificar el código. Ahora debe agregar el parámetro para llamar Foo(), por lo que ahora se convierte en:

std::for_each(vec.begin(), vec.end(), std::bind2nd(Foo(), X)) 

pero eso es sólo una solución temporal. Ahora el proyecto está madurando y usted entiende la lógica empresarial mucho mejor y desea agregar nuevas modificaciones al código. Es en este punto que se da cuenta de que debe usar el bien anterior:

for(std::vector::iterator it = vec.begin(); it != vec.end(); ++it) 

¿Esto me está sucediendo solo a mí? ¿Reconoces este tipo de patrón en tu código? ¿Ha experimentado patrones similares usando STL?

+1

Por cierto, si en su segundo ejemplo, "X" es el mismo para todos los elementos. Solo pásalo al constructor de Foo y guárdalo en el funtor en lugar de unirlo. Mucho más simple –

+0

En realidad, no está utilizando ninguna de las STL, por lo que está a salvo :) –

+0

Solo una opinión, pero "demasiado" es cuando utiliza funciones que no necesita únicamente para usarlas. Si es útil, úselo. Si le preocupan los nombres excesivamente largos, siempre puede usar un alias typedef o namespace para acortarlos (por ejemplo, 'typedef std :: vector :: iterator VecIter;'). Lo que ocurre con la biblioteca estándar es que, por lo general, es la forma más limpia de crear un compilador en un caso general, simplemente porque los creadores del compilador o las personas que mejor lo conocen (si no los creadores) escribirán su implementación. No tengas miedo de usarlo cuando sea útil. –

Respuesta

10

El uso de boost::bind con std :: for_each resuelve este problema de una manera limpia. O puede usar BOOST_FOREACH.

Ejemplo de std :: for_each:

std::for_each(v.begin(), v.end(), boost::bind(&C::f, _1, param)); 

Ejemplo de BOOST_FOREACH:

std::list<int> list_int(/*...*/); 
BOOST_FOREACH(int i, list_int) 
{ 
    // do something with i 
} 
+0

... hasta llegar a 10 parámetros, eso es! :) – Kylotan

+1

en cuyo punto los agrupa dentro de una estructura :) –

+2

No, en ese punto usted reconsidera la arquitectura que requiere que una función tenga 10 parámetros;) –

3

Similar a su problema, a menudo se dio cuenta de que el "funtor" patrón/idioma en C++ es en realidad bastante pesado. Es por eso que estoy esperando Lambda Functions en C++ 0X. Algo de eso es posible con boost :: lambda ahora.

+0

OMG, la sintaxis ... 0X tiene 8 meses más hasta que termina más de 3 años hasta que los principales proveedores de compiladores se pongan al día. Eso será un largo tiempo. –

+1

@Anton: Ya está en g ++ y Visual Studio 10 (RC disponible gratuitamente ahora) –

10

Puede ir en la dirección opuesta también. Supongamos que comienza con una operación que solo requiere un par de líneas. Usted no quiere preocuparse por la creación de una función que sólo se llama una vez, sólo para condensar el bucle, por lo que escribir algo como:

for() 
{ 
    // do 
    // some 
    // stuff 
} 

Luego, cuando la operación que debe realizar se vuelve más complejo, se da cuenta que tirando de él en una función separada tiene sentido por lo que terminan con

for() 
    do_alot_more_stuff(); 

Y luego modificarlo para ser como su método original tiene sentido para condensarlo abajo más lejos:

std::for_each(begin, end, do_alot_more_stuff); 

Al final, ¿qué tan difícil es realmente cambiar un for_each a un ciclo for, o viceversa? ¡No te rindas ante pequeños detalles!

5

Úselo como cualquier otra herramienta de idioma. Cuando te haga la vida más fácil, úsalo. Cuando se vuelve engorroso, haga otra cosa. No es que sea realmente difícil refactorizar un ciclo de una manera u otra, cuando cambian los requisitos.

+0

Exactamente. ¿Qué pasa con el cambio de código? –

0

También piense en Paralelismo, con una función puede definir qué cambiará e indicar si un rango de elementos se puede hacer en paralelo en vez de 1 a la vez de principio a fin.

1

mejor ha usado for_each en lugar de transformar en el primer lugar ...

1

nunca uso std :: for_each (o muy rara vez).

Sugiero usar Boost.Foreach y construcciones clásicas "para" por ahora. Y cuando C++ 0x está fuera, podría considerar usar el nuevo constructo "for", que se hace más legible para iterar a través de los contenedores.

+1

Difícilmente puede esperar que C++ obtenga un verdadero bucle "for" (en lugar del bucle while glorificado que tiene ahora). –

0

O usted podría esperar para C++ 0x y utilizar for(elem& e, container){e.something();}
exactamente lo mismo que BOOST_FOREACH(), sino que forma parte de la norma (en algunos años ...).

2

He tenido el mismo problema con muchas cosas en Algorithm. Tiene una desagradable tendencia a convertirse en más código que acaba de usar un bucle for old-fashioned.

No puedo justificar realmente irme y crear alguna clase de functor especial (que es un tema moderadamente avanzado en C++ que muchos de mis mantenedores no entenderán del todo) con un constructor y un destructor apropiados, y tal vez algunos descriptores de acceso, simplemente para evitar un ciclo de una línea.