Viene prodotto generalmente raccomandato migliori pratiche 1 per uso passaggio da ref const per tutti i tipi , eccetto incorporato tipi ( char
, int
, double
, etc.), per iteratori e oggetti funzione (lambda, classi derivanti da std::*_function
).
Ciò era particolarmente vero prima dell'esistenza della semantica di mosse . Il motivo è semplice: se si passa per valore, è necessario creare una copia dell'oggetto e, ad eccezione di oggetti molto piccoli, è sempre più costoso che passare un riferimento.
Con C ++ 11 abbiamo acquisito la semantica dei movimenti . In poche parole, spostare la semantica consente che, in alcuni casi, un oggetto possa essere passato "per valore" senza copiarlo. In particolare, questo è il caso in cui l'oggetto che si sta passando è un valore .
Di per sé, spostare un oggetto è ancora costoso almeno quanto passare per riferimento. Tuttavia, in molti casi una funzione copierà comunque internamente un oggetto, ovvero assumerà la proprietà dell'argomento. 2
In queste situazioni abbiamo il seguente compromesso (semplificato):
- Possiamo passare l'oggetto per riferimento, quindi copiarlo internamente.
- Possiamo passare l'oggetto per valore.
"Passa per valore" fa comunque copiare l'oggetto, a meno che l'oggetto non sia un valore. Nel caso di un valore, l'oggetto può invece essere spostato, in modo che il secondo caso non sia più improvvisamente "copia, quindi sposta" ma "sposta, quindi (potenzialmente) sposta di nuovo".
Per oggetti di grandi dimensioni che implementano costruttori di mosse adeguati (come vettori, stringhe ...), il secondo caso è quindi molto più efficiente del primo. Pertanto, si consiglia di utilizzare il passaggio per valore se la funzione diventa proprietaria dell'argomento e se il tipo di oggetto supporta uno spostamento efficiente .
Una nota storica:
In effetti, qualsiasi compilatore moderno dovrebbe essere in grado di capire quando passare per valore è costoso e, se possibile, convertire implicitamente la chiamata per utilizzare un riferimento const.
In teoria.In pratica, i compilatori non possono sempre cambiarlo senza interrompere l'interfaccia binaria della funzione. In alcuni casi speciali (quando la funzione è incorporata) la copia verrà effettivamente elusa se il compilatore riesce a capire che l'oggetto originale non verrà modificato attraverso le azioni nella funzione.
Ma in generale il compilatore non può determinarlo, e l'avvento della semantica di spostamento in C ++ ha reso questa ottimizzazione molto meno rilevante.
1 Ad esempio in Scott Meyers, C ++ efficace .
2 Questo è particolarmente vero per i costruttori di oggetti, che possono prendere argomenti e archiviarli internamente per far parte dello stato dell'oggetto costruito.