2011-11-19 18 views
13

Compara funciones de integración genéricas:Pasando objeto funtor por valor vs por referencia (C++)

template <class F> double integrate(F integrand); 

con

template <class F> double integrate(F& integrand); 

o

template <class F> double integrate(const F& integrand); 

¿Cuáles son los pros y los contras de cada ? STL usa el primer enfoque (pasar por valor), ¿significa que es el más universal?

+0

STL generalmente utiliza el primer enfoque porque surgen muchos problemas cuando utiliza contenedores de referencias, etc. –

+2

Igual que en cualquier otro lugar: dependiendo de qué 'F' es, estas versiones pueden variar de ser idénticas a muy diferentes. Si 'F' es con estado, solo la versión intermedia podría ser posible. –

+0

Básicamente, está imponiendo requisitos a los usuarios, cualquiera que sea la forma que elija. Si por valor, necesita que le proporcionen un functor que pueda copiarse sin perder integridad. Si es por referencia, entonces está requiriendo que le den algo con una duración de por vida apropiada para el usuario que lo esté colocando. – Mordachai

Respuesta

19

Los objetos de función generalmente deberían ser pequeños, por lo que no creo que pasarlos por valor vaya a tener un rendimiento notorio (compárelo con el trabajo que realiza la función en su cuerpo). Si pasa por valor, también puede obtener beneficios del análisis de código, porque un parámetro de valor por valor es local para la función y el optimizador puede indicar cuándo y cuándo no se puede omitir una carga de un miembro de datos del administrador.

Si el funtor es apátrida, pasarlo como argumento no implica ningún costo en absoluto: el byte de relleno que utiliza el funtor no tiene que tener ningún valor en particular (en el Itanium Abi usado al menos por GCC). Al usar referencias, siempre debe pasar una dirección.

El último (const T&) tiene el inconveniente de que en C++ 03 que no funciona para las funciones sin formato, porque en C++ 03 el programa está mal formado si intentas aplicar const a un tipo de función (y es un caso SFINAE). Las implementaciones más recientes ignoran const cuando se aplican a tipos de funciones.

El segundo inconveniente (T&) tiene el inconveniente obvio de que no se pueden pasar los funtores temporales.

Para resumir, en general los pasaría por alto, a menos que vea un claro beneficio en casos concretos.

3

Dado el contexto, se espera que F a ser un "objeto exigible" (algo así como una función libre o de una clase que tiene un operador() definido)

Ahora, dado que un nombre de función libre no puede ser un L- valor, la segunda versión no es adecuada para eso. El tercero asume que F :: operator() es const (pero puede no ser el caso, si es necesario para alterar el estado de F) El primero funciona en una "copia propia", pero requiere que F se pueda copiar.

Ninguno de los tres es "universal", pero el primero es muy probable que funcione en los casos más comunes.

5

STL utiliza el primer enfoque (paso por valor)

Claro, las bibliotecas estándar pase iteradores y funtores por valor. Se supone (con razón o sin ella) que es barato copiarlo, y esto significa que si escribe un iterador o un functor que es costoso copiar, es posible que tenga que encontrar la manera de optimizarlo más adelante.

Pero eso es solo para los propósitos para los que las bibliotecas estándar usan funtores: en su mayoría son predicados, aunque también hay cosas como std::transform. Si está integrando una función, eso sugiere algún tipo de biblioteca matemática, en cuyo caso supongo que es mucho más probable que trabaje con funciones que conllevan un gran estado. Por ejemplo, podría tener una clase que represente polinomios de orden n, con n + 1 coeficientes como miembros de datos no estáticos.

En ese caso, una referencia constante podría ser mejor. Al usar dicho functor en algoritmos estándar como transform, puede envolverlo en una pequeña clase que realice un direccionamiento indirecto a través de un puntero, para asegurarse de que sigue siendo barato copiarlo.

Tomar una referencia no constante es potencialmente molesto para los usuarios, ya que les impide pasar temporarios.

Cuestiones relacionadas