Dove dovrei preferire il pass-by-reference o il pass-by-value?

In quali circostanze dovrei preferire il riferimento pass-by? Pass-by-value?

Esistono cinque casi principali in cui è necessario utilizzare il pass-by-reference rispetto al valore pass-by:

  1. Se chiami una funzione che deve modificare i suoi argomenti, usa pass-by-reference come unico modo per ottenere questo effetto (tratto pass-by-reference e pass-by-pointer in modo intercambiabile in questo caso, sebbene con pass -del puntatore si deve spesso controllare esplicitamente per NULL).
  2. Se si chiama una funzione che deve prendere un object grande come parametro, passarlo per riferimento const per evitare di eseguire una copia non necessaria di quell’object e ottenere un grande successo di efficienza.
  3. Se stai scrivendo un costruttore di copie che per definizione deve prendere un riferimento, usa pass per riferimento.
  4. Se stai scrivendo una funzione che vuole operare su una class polimorfica, usa pass per riferimento o passa per puntatore per evitare di affettare.
  5. Se stai scrivendo una funzione che potrebbe restituire un object molto big o non copiato, usa pass per riferimento come modo per utilizzare un parametro per memorizzare il valore prodotto.

Ci sono diverse considerazioni, tra cui:

Prestazione

Passare per valore copia i dati, quindi il passaggio di strutture di dati di grandi dimensioni in base al valore può inibire le prestazioni. Il passaggio per riferimento passa solo un riferimento (in pratica l’indirizzo) ai dati. Per le strutture di dati di grandi dimensioni, questo può migliorare notevolmente le prestazioni. Per strutture di dati più piccole (come un int), il passaggio per riferimento può inibire le prestazioni.

modifiche

Passando in base al valore, i dati vengono copiati, pertanto se il codice di destinazione modifica quella copia, ciò non influirà sull’originale. Il passaggio per riferimento passa solo l’indirizzo dei dati, quindi le modifiche apportate a tale riferimento saranno “visibili” al codice chiamante.

Sì.

Passa in base al valore per cose come i tipi nativi che sono abbastanza piccoli da renderli efficienti. Altrimenti usa il passaggio per riferimento ( const ).

La parte difficile è la scrittura di un modello che può essere applicato a entrambi (nel qual caso, di solito si usa il pass per riferimento – la penalità potenziale per passare un object di grandi dimensioni per valore è molto peggiore della penalità potenziale per il passaggio per riferimento quando si passa in base al valore sarebbe stato preferito).

Modifica: questo, ovviamente, presuppone una situazione in cui la semantica richiesta consentirebbe a entrambi: ovviamente se stai lavorando con qualcosa come oggetti polimorfi, non c’è una vera “preferenza”, perché devi usare un puntatore o un riferimento a ottenere un comportamento corretto.

Come altri già hanno risposto alla tua domanda sufficientemente bene, vorrei aggiungere un punto importante:

Se la class non ha public costruttore di copie public , allora non hai la possibilità di passare per valore; devi passare per riferimento (o puoi passare il puntatore).

Il seguente programma non verrebbe compilato:

 class A { public: A(){} private: A(const A&) {} }; //source of error : pass by value void f(A ) {} int main() { A a; f(a); return 0; } 

Errore:

prog.cpp: nella funzione ‘int main ()’:
prog.cpp: 10: errore: ‘A :: A (const A &)’ è privato
prog.cpp: 18: errore: in questo contesto
prog.cpp: 18: errore: inizializzazione dell’argomento 1 di ‘void f (A)’

Vedi te stesso su ideone: http://www.ideone.com/b2WLi

Ma una volta eseguita la funzione f passa per riferimento, quindi compila bene: http://www.ideone.com/i6XXB

Hai taggato la tua domanda con C e C ++.

Pertanto, ti suggerisco di prendere in considerazione l’utilizzo del passaggio per riferimento in C ++ che supporta questa funzione e che non consideri di utilizzarlo in C che non supporta questa funzione.

Mentre i riferimenti sono riferimenti, “riferimento” in c ++ di solito si riferisce alla pratica di taggare un parametro di SomeType &.

Che non dovresti mai fare. L’unico posto appropriato è una syntax magica necessaria per implementare i vari operatori predefiniti. Altrimenti:

  • Non si devono mai passare parametri per riferimento: passare per puntatore, altrimenti si rendono le revisioni del codice quasi impossibili. Passare per riferimento rende imansible capire esaminando una chiamata in base alla quale i parametri possono essere modificati.

  • Non si dovrebbe mai passare in parametro per riferimento neanche. Di nuovo, questo significa che stai eseguendo una meta ottimizzazione. Devi sempre passare per valore, altrimenti sei colpevole di sbirciare all’interno di un object, esaminandone l’implementazione e decidendo che il pass-by-reference è preferito per qualche motivo.

Qualsiasi class c ++ dovrebbe implementare tutti i costruttori di copia e assegnazione e i sovraccarichi necessari per essere passati in giro per valore. Altrimenti non ha fatto il suo lavoro, di astrarre il programmatore dai dettagli di implementazione della class.