Yo diría que las funciones reciben parámetros por referencia cuando se necesita o cuando conviene, otras veces convendrá pasar por valor (copia) y otras por dirección (puntero).
Aquí van algunos ejemplos elementales...
si tienes que diseñar una función "suma", que tome dos enteros y devuelva la suma, esos dos enteros se pasarán por valor, es más eficiente que pasarlos por referencia.
Si la función opera sobre algún objeto grande, probablemente convenga pasarlo por referencia. Si se pretende modificar será una referencia a secas; si no se pretende modificar, será una referencia constante.
Cuando se necesita que la función opere sobre una copia del argumento de llamada, en general conviene dejar al compilador que la haga, los parámetros de la función son un muy buen lugar para eso. Por ejemplo, si se desea pasar todos los caracteres de una string a mayúsculas sin modificar la string original:
Hay otros casos en que la cosa es al revés; por ejemplo, si la función va a tomar como argumento un objeto temporal (un rValue), probablemente se prefiera un parámetro por valor y asignarlo usando "std::move". (must see https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11)
... El C++ es un lenguaje potente pero complejo.