2009-03-19 17 views
10

Acabo de leer en el estándar C++ que std::for_each es una operación de secuencia no modificante, junto con find, search y así sucesivamente. ¿Eso significa que la función aplicada a cada elemento no debería modificarlos? ¿Porqué es eso? ¿Qué podría salir mal?¿Por qué std :: for_each es una operación de secuencia no modificante?

Aquí hay un código de muestra, donde se modifica la secuencia. ¿Puedes ver algo mal con eso?

void foo(int & i) 
{ 
    i = 12; 
} 

int main() 
{ 
    std::vector<int> v; 
    v.push_back(0); 

    std::for_each(v.begin(), v.end(), foo); 
    // v now contains 12 
} 

Sospecho que esto es solo un problema de interpretación, pero quería opinar sobre eso.

PD: Sé que podría usar std::transform en lugar de for_each, pero ese no es el punto.

Respuesta

16

Ver this defect report dicen

El GDP cree que nada en la norma prohíbe a los objetos de función que modifican la secuencia de elementos. El problema es que for_each está en una sección titulada "algoritmos no conmutadores", y el título puede ser confuso. Una nota no normativa debería aclarar eso.

Pero también la nota this one.

Ellos parece que lo llaman "no modificación" porque for_each sí mismo no exlicitly modificar los elementos de la secuencia.

+0

Sí, acabo de encontrar la misma lista de problemas. Como suponía, era solo una cuestión de interpretación (pero realmente creo que deberían agregar esta nota aclaratoria). –

+0

sí, yo también pienso. todavía no está en n2800. veamos qué contiene el próximo borrador. como la nota tiene el estado de CD1, es bastante extraño que ya no esté :) sospecho que lo eliminaron porque quieren elaborar un concepto para ello. –

+0

¡Buen hallazgo! En particular, tenga en cuenta esto en el informe de defectos: "El documento STL original de Stepanov y Lee prohibía explícitamente que el objeto de función modificara su argumento". No estaba enterado de eso. –

20

En pocas palabras, no puede hacer un cambio que podría modificar la estructura del contenedor. Esto se debe a que, en el caso general, modificar un contenedor puede invalidar los iteradores que se utilizan.

Puede modificar el elemento siempre que no cambie la estructura del contenedor (como el orden de los elementos en el contenedor).

[Además]


Tenga en cuenta que parece que hay cierta confusión acerca de for_each ser un algoritmo de 'no modificar'. Esta situación confusa se resume aquí en Stroustrup en errata para la 4ª impresión de "The C++ Programming Language, 3rd Ed." (CPL ) tiene esto que decir acerca de si for_each puede modificar los elementos de una secuencia (http://www.research.att.com/~bs/3rd_printing5.html):

"El algoritmo for_each() se clasifica como nonmodifying ya que no modifica de manera explícita una secuencia Sin embargo, si. aplicado a una secuencia no const for_each() puede cambiar los elementos de la secuencia. Para un ejemplo, vea el uso de negate() en 11.9. " (resolución de estándares recientes).

El CPL originalmente indicó que el objeto de función o la función pasa a for_each no se le permitió modificar el elemento se le ha pasado. Sin embargo, la CPL se escribió y se publicó originalmente antes de que se finalizara la norma, y ​​aparentemente esta restricción en for_each() se eliminó antes de que se finalizara.

Consulte también:

6

creo "para no modificar las operaciones de secuencia" significa que esta operación no modifica secuencia. Pero la operación podría modificar los elementos del contenedor.

Valor de los elementos del contenedor y secuencia - cosas diferentes.

2

Como litb indicado anteriormente, el for_each se clasifica como un 'algoritmo de nonmutating'

STL de 'mutación' contrapartida de que es std :: transformar.

Puesto que usted ha indicado Conoce puede utilizar std :: transformar, lo anterior se convierte realmente en el punto. Sirve como un punto de comunicación para las personas que leen su código.

Si veo std :: for_each, es evidente que todo lo que hace foo, no modificará el contenedor.

La pauta sigo puede afirmar:

"Si desea utilizar los elementos de un contenedor que hacer alguna tarea que no cambia los elementos, utilizar std :: for_each

Si. desear usar los elementos de un contenedor para modificar los elementos de alguna manera sistémica o usarlos en una tarea que los cambie de alguna manera, use std :: transform. "

Cuestiones relacionadas