Perché passare per riferimento const anziché per valore?

Da quanto ho capito: quando passi di valore, la funzione crea una copia locale dell’argomento passato e la usa; quando la funzione termina, diventa fuori portata. Quando si passa da riferimento const, la funzione utilizza un riferimento all’argomento passato che non può essere modificato. Non capisco, tuttavia, perché uno dovrebbe scegliere uno sull’altro, tranne in una situazione in cui un argomento deve essere modificato e restituito. Se avessi una funzione di vuoto in cui non viene restituito nulla, perché sceglierne uno rispetto all’altro?

EDIT: Quindi passando di riferimento const evita di copiare l’object. Quindi in quali situazioni si copia bene l’object? Voglio dire, perché non usare sempre i riferimenti const sempre se ottimizza continuamente le prestazioni?

Ci sono due considerazioni principali. Uno è la spesa per copiare l’object passato e il secondo è l’ipotesi che il compilatore può fare quando l’object è un object locale.

Es. Nella prima forma, nel corpo di f non si può presumere che a e b non facciano riferimento allo stesso object; quindi il valore di a deve essere riletto dopo ogni scrittura in b , nel caso in cui. Nel secondo modulo, a non può essere modificato tramite una scrittura su b , poiché è locale per la funzione, quindi queste rilette non sono necessarie.

 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 } 

Ad esempio: nel primo esempio, il compilatore può essere in grado di assumere che il valore di un object locale non cambia quando viene effettuata una chiamata non correlata. Senza informazioni su h , il compilatore potrebbe non sapere se un object a cui quella funzione ha un riferimento (tramite un parametro di riferimento) non è stato modificato da h . Ad esempio, quell’object potrebbe essere parte di uno stato globale che viene modificato da 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 // ... } 

Sfortunatamente, questo esempio non è in ghisa. È ansible scrivere una class che, ad esempio, aggiunge un puntatore a se stesso a un object di stato globale nel suo costruttore, in modo che anche un object locale di tipo class possa essere modificato da una chiamata di funzione globale. Nonostante ciò, ci sono ancora potenzialmente maggiori opportunità di ottimizzazioni valide per gli oggetti locali in quanto non possono essere alias direttamente direttamente dai riferimenti passati o da altri oggetti preesistenti.

Il passaggio di un parametro mediante riferimento const deve essere scelto dove la semantica dei riferimenti è effettivamente richiesta o come miglioramento delle prestazioni solo se il costo del potenziale aliasing viene superato dalle spese di copia del parametro.

Passare argomenti in base al valore e quindi copiarli può essere costoso: i riferimenti const evitano quel passo costoso pur promettendo al chiamante che l’object non verrà modificato.

Solitamente i tipi fondamentali ( int , double , …) vengono passati per valore, mentre i tipi di class vengono passati per riferimento const.

Possono tuttavia esserci delle eccezioni in cui il valore pass-by per i tipi di class può essere vantaggioso.

Effettuare una copia di un object potrebbe influire notevolmente sulle prestazioni in alcuni casi. Considera una funzione il cui argomento sarà std::vector e vuoi passare vettore con 1 milione di elementi. In questo caso, ti consigliamo di utilizzare il riferimento const passando per valore. In questa domanda SO puoi trovare una semplice regola generale per la tua domanda.

A volte, fare una copia di un object può essere costoso e quindi il riferimento pass-by-const eviterà di dover fare quella copia. Altrimenti, direi che dovresti semplicemente passare per valore se è ciò che è semanticamente richiesto.

Passare un argomento per valore ha il sovraccarico di una copia dell’object che viene passato alla funzione.

Forse un object non è copiabile e le tue scelte sono limitate.

A causa dei vantaggi prestazionali che otterrai. Diciamo che hai un object grande (in termini di dimensioni in byte). Ora, se si passa questo object per valore a una funzione, è necessario creare una copia non necessaria di questo, tuttavia è ansible ottenere lo stesso effetto passando un riferimento const a quell’object stesso senza creare copia. Poiché un riferimento è normalmente memorizzato come un puntatore sotto i cappucci, il costo del passaggio di un riferimento è solo sizeof(pointer) .

Un array non può essere passato per valore, quindi è un buon momento per usare un puntatore const.

Per evitare di fare una copia non necessaria , migliorando così le prestazioni.