Le operazioni di spostamento (come il costruttore di spostamenti) std::shared_ptr
sono economiche , in quanto sostanzialmente "rubano puntatori" (dalla sorgente alla destinazione; per essere più precisi, l'intero blocco di controllo dello stato viene "rubato" dalla sorgente alla destinazione, comprese le informazioni sul conteggio dei riferimenti) .
Invece le operazioni di copiastd::shared_ptr
sull'invocazione aumentano il conteggio dei riferimenti atomici (cioè non solo ++RefCount
su un RefCount
membro di dati interi , ma ad esempio chiamando InterlockedIncrement
su Windows), che è più costoso del semplice rubare puntatori / stato.
Quindi, analizzando in dettaglio la dinamica del conteggio di riferimento di questo caso:
// shared_ptr<CompilerInvocation> sp;
compilerInstance.setInvocation(sp);
Se passi sp
per valore e poi ne esegui una copia all'interno del CompilerInstance::setInvocation
metodo, hai:
- Quando si immette il metodo, il
shared_ptr
parametro viene creato come copia: incremento del conteggio atomico .
- All'interno del corpo del metodo, si copia il
shared_ptr
parametro nel membro dati: ref count incremento atomico .
- All'uscita dal metodo, il
shared_ptr
parametro viene distrutto: ref count decremento atomico .
Hai due incrementi atomici e un decremento atomico, per un totale di tre operazioni atomiche .
Invece, se passi il shared_ptr
parametro per valore e poi std::move
all'interno del metodo (come correttamente fatto nel codice di Clang), hai:
- Quando si immette il metodo, il
shared_ptr
parametro viene creato come copia: incremento del conteggio atomico .
- All'interno del corpo del metodo, è
std::move
il shared_ptr
parametro nell'elemento dati: il conteggio dei riferimenti non cambia! Stai solo rubando puntatori / stato: non sono coinvolte costose operazioni di conteggio dei riferimenti atomici.
- All'uscita dal metodo, il
shared_ptr
parametro viene distrutto; ma poiché ti sei spostato nel passaggio 2, non c'è nulla da distruggere, poiché il shared_ptr
parametro non punta più a nulla. Ancora una volta, in questo caso non si verifica alcun decremento atomico.
In conclusione: in questo caso si ottiene solo un incremento atomico del conteggio dei riferimenti, ovvero solo un'operazione atomica .
Come puoi vedere, è molto meglio di due incrementi atomici più un decremento atomico (per un totale di tre operazioni atomiche) per il caso della copia.