Si desea rendimiento, pase por valor si lo está almacenando.
Supongamos que tiene una función llamada "ejecutar esto en el hilo de la interfaz de usuario".
std::future<void> run_in_ui_thread( std::function<void()> )
que ejecuta un código en el subproceso "ui", luego señala el future
cuando está hecho. (Útil en los marcos de la interfaz de usuario donde el hilo de la interfaz de usuario es donde se supone que debes jugar con los elementos de la interfaz de usuario)
Tenemos dos firmas que estamos considerando:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Ahora, es probable que usemos estos de la siguiente manera:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
que creará un cierre anónimo (una lambda), construirá un std::function
fuera de él, lo pasará a la run_in_ui_thread
función y luego esperará a que termine de ejecutarse en el hilo principal.
En el caso (A), std::function
se construye directamente a partir de nuestra lambda, que luego se utiliza dentro de run_in_ui_thread
. La lambda se move
introduce en el std::function
, por lo que cualquier estado móvil se transporta de manera eficiente.
En el segundo caso, std::function
se crea un temporal , se move
introduce el lambda en él, luego ese temporal std::function
se usa como referencia dentro del run_in_ui_thread
.
Hasta ahora, todo bien: los dos se desempeñan de manera idéntica. ¡Excepto run_in_ui_thread
que va a hacer una copia de su argumento de función para enviar al hilo ui para ejecutar! (regresará antes de terminar con él, por lo que no puede simplemente usar una referencia a él). Para el caso (A), simplemente move
el std::function
en su almacenamiento a largo plazo. En el caso (B), nos vemos obligados a copiar el std::function
.
Esa tienda hace que pasar por valor sea más óptimo. Si existe alguna posibilidad de que esté almacenando una copia del std::function
pase por valor. De lo contrario, de cualquier manera es más o menos equivalente: el único inconveniente del std::function
sub -valor es si está tomando el mismo voluminoso y tiene un método secundario tras otro. Salvo eso, a move
será tan eficiente como a const&
.
Ahora, hay algunas otras diferencias entre los dos que se aplican principalmente si tenemos un estado persistente dentro del std::function
.
Suponga que std::function
almacena algún objeto con a operator() const
, pero también tiene algunos mutable
miembros de datos que modifica (¡qué grosero!).
En el std::function<> const&
caso, los mutable
miembros de datos modificados se propagarán fuera de la llamada a la función. En el std::function<>
caso, no lo harán.
Este es un caso de esquina relativamente extraño.
Desea tratar std::function
como lo haría con cualquier otro tipo posiblemente pesado y de bajo costo. Mudarse es barato, copiar puede ser costoso.
sizeof(std::function)
no ser más que2 * sizeof(size_t)
, que es el tamaño mínimo que alguna vez consideraría para una referencia constante.