Por que passar por referência const em vez de por valor?

Pelo que entendi: quando você passa por valor, a function faz uma cópia local do argumento passado e usa isso; quando a function termina, sai do escopo. Quando você passa por referência const, a function usa uma referência ao argumento passado que não pode ser modificado. Eu não entendo, no entanto, por que um escolheria um sobre o outro, exceto em uma situação onde um argumento precisa ser modificado e retornado. Se você tivesse uma function vazia em que nada é retornado, por que escolher uma sobre a outra?

EDIT: Então, basicamente, passando por referência const evita copiar o object. Então, em que situações copiar o object é bom? Quero dizer, por que não usar referências constantes sempre que isso otimiza o desempenho o tempo todo?

Existem duas considerações principais. Uma é a despesa de copiar o object passado e a segunda é as suposições que o compilador pode fazer quando o object é um object local.

Por exemplo, na primeira forma, no corpo de f não pode ser assumido que a e b não fazem referência ao mesmo object; então o valor de a deve ser relido depois de qualquer gravação em b , apenas no caso. No segundo formulário, a não pode ser alterado por meio de uma gravação para b , pois é local para a function, portanto, essas releituras são desnecessárias.

 void f(const Obj& a, Obj& b) { // a and b could reference the same object } void f(Obj a, Obj& b) { // a is local, b cannot be a reference to a } 

Por exemplo: No primeiro exemplo, o compilador pode ser capaz de assumir que o valor de um object local não muda quando uma chamada não relacionada é feita. Sem informações sobre h , o compilador pode não saber se um object ao qual essa function tem uma referência (via um parâmetro de referência) não é alterado por h . Por exemplo, esse object pode ser parte de um estado global modificado por h .

 void g(const Obj& a) { // ... h(); // the value of a might change // ... } void g(Obj a) { // ... h(); // the value of a is unlikely to change // ... } 

Infelizmente, este exemplo não é ferro fundido. É possível escrever uma class que, por exemplo, adiciona um ponteiro a si mesmo a um object de estado global em seu construtor, para que até mesmo um object local do tipo de class possa ser alterado por uma chamada de function global. Apesar disso, ainda há potencialmente mais oportunidades para otimizações válidas para objects locais, pois não podem ser alias diretamente por referências passadas ou outros objects pré-existentes.

A passagem de um parâmetro por referência const deve ser escolhida onde a semântica das referências é realmente necessária, ou como melhoria de desempenho apenas se o custo do potencial aliasing fosse compensado pela despesa de copiar o parâmetro.

Passar argumentos por valor e, assim, copiá-los pode ser caro – referências constantes evitam esse passo caro e ainda prometem ao chamador que o object não será alterado.

Geralmente os tipos fundamentais ( int , double , …) são passados ​​por valor, enquanto os tipos de class são passados ​​por referência const.

No entanto, pode haver exceções em que o valor de passagem para tipos de class pode ser benéfico.

Fazer uma cópia de um object pode afetar muito o desempenho em alguns casos. Considere uma function cujo argumento será std::vector e você deseja passar vetor com 1 milhão de elementos. Nesse caso, você desejará usar a referência const passando por valor. Nesta pergunta SO você pode encontrar uma regra geral simples para sua pergunta.

Às vezes, fazer uma cópia de um object pode ser dispendioso e, assim, passar por referência const evitará ter que fazer essa cópia. Caso contrário, eu diria que você deve simplesmente passar por valor, se isso é o que é semanticamente necessário.

Passar um argumento por valor tem a sobrecarga de uma cópia do object sendo passado para a function.

Talvez um object não seja copiável e suas escolhas sejam limitadas.

Por causa dos benefícios de desempenho que você terá. Vamos dizer que você tem um grande object (em termos de tamanho em bytes). Agora, se você passar este object por valor para uma function, uma cópia desnecessária precisa ser criada, mas você pode obter o mesmo efeito passando uma referência const ao próprio object sem criar uma cópia. Como uma referência é normalmente armazenada como um ponteiro sob os capôs, o custo de passar uma referência é apenas sizeof(pointer) .

Uma matriz não pode ser passada por valor, portanto, este é um bom momento para usar um ponteiro const.

Evitar fazer uma cópia desnecessária , melhorando assim o desempenho.