simple secuenciales secuencial resueltos flujo estructuras estructura ejercicios ejemplos ejemplo diagrama control busqueda c++ c++11 stl-algorithm

c++ - secuenciales - ¿Por qué los predicados de algoritmos de operación de secuencia se pasan por copia?



estructura secuencial simple (3)

Es sobre todo por razones históricas. En el ''98, cuando todo el contenido de algo se convirtió en las referencias estándar, tuvo todo tipo de problemas. Eso se resolvió finalmente a través de los DR de la biblioteca y el núcleo mediante C ++ 03 y más allá. También los ref-wrappers y las encuadernaciones que realmente funcionan solo llegaron a TR1.

Aquellos que probaron el uso de algos con C ++ 98 que tienen funciones que usan parámetros o ref de ref pueden recordar todo tipo de problemas. Los algos autoescritos también fueron propensos a golpear el temido problema ''referencia a referencia'' .

Pasar por valor al menos funcionó bien, y apenas creó muchos problemas, y boost tuvo ref y cref desde el principio para ayudarlo donde lo necesitaba.

Me pregunto por qué los funtores se pasan por copia a las funciones de algorithm :

template <typename T> struct summatory { summatory() : result(T()) {} void operator()(const T& value) { result += value; std::cout << value << "; ";}; T result; }; std::array<int, 10> a {{ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 }}; summatory<int> sum; std::cout << "/nThe summation of: "; std::for_each(a.begin(), a.end(), sum); std::cout << "is: " << sum.result;

Esperaba la siguiente salida:

La suma de: 1; 1; 2; 3; 5; 8; 13; 21; 34; 55; es: 143

Pero sum.result contiene 0 , que es el valor predeterminado asignado en el ctor. La única forma de lograr el comportamiento deseado es capturar el valor de retorno de for_each :

sum = std::for_each(a.begin(), a.end(), sum); std::cout << "is: " << sum.result;

Esto sucede porque el functor se pasa por copia a for_each lugar de por referencia:

template< class InputIt, class UnaryFunction > UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

Así que el funtor externo permanece intacto, mientras que el interno (que es una copia del externo) se actualiza y se devuelve después de realizar el algoritmo ( demostración en vivo ), por lo que el resultado se copia (o se mueve) nuevamente después de realizar todas las operaciones.

Debe haber una buena razón para hacer el trabajo de esta manera, pero realmente no me doy cuenta de la razón de este diseño, por lo que mis preguntas son:

  • ¿Por qué los predicados de los algoritmos de operación de secuencia se pasan por copia en lugar de por referencia?
  • ¿Qué ventajas ofrece el enfoque de paso por copia frente al de paso por referencia?

Esto es puramente una conjetura, pero ...

... Supongamos por un momento que toma por referencia a const. Esto significaría que todos sus miembros deben ser mutables y el operador debe ser constante. Eso simplemente no se siente "bien".

... Supongamos por un momento que toma por referencia a no const. Se llamaría un operador no constante, los miembros solo pueden trabajar bien. ¿Pero qué pasa si quieres pasar un objeto ad-hoc? ¿Como el resultado de una operación de enlace (incluso C ++ 98 tenía herramientas de enlace feas y simples)? O el tipo en sí mismo hace todo lo que necesitas y no necesitas el objeto después de eso y solo quieres llamarlo como for_each(b,e,my_functor()); ? Eso no funcionará ya que los temporales no pueden vincularse a referencias no constantes.

Quizás no sea la mejor, pero la opción menos mala está aquí para tomar el valor, copiarlo en el proceso tanto como sea necesario (con suerte, no muy a menudo) y luego, cuando termine, devuélvalo de for_each. Esto funciona bien con la complejidad bastante baja de su objeto sumatorio, no necesita agregar elementos mutables como el enfoque de referencia a const, y funciona con temporarios también.

Pero YMMV, y es muy probable que lo hicieran los miembros del comité, y supongo que al final fue una votación sobre lo que pensaron que es más probable que se ajuste a la mayoría de los casos de uso.


Tal vez esto podría ser una solución. Captura el funtor como referencia y llámalo en un lambda

std::for_each(a.begin(), a.end(), [&sum] (T& value) { sum(value); }); std::cout << "is: " << sum.result;