Le operazioni di spostamento (come il costruttore di spostamenti) std::shared_ptrsono 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 ++RefCountsu un RefCountmembro di dati interi , ma ad esempio chiamando InterlockedIncrementsu 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 spper valore e poi ne esegui una copia all'interno del CompilerInstance::setInvocationmetodo, hai:
- Quando si immette il metodo, il
shared_ptrparametro viene creato come copia: incremento del conteggio atomico .
- All'interno del corpo del metodo, si copia il
shared_ptrparametro nel membro dati: ref count incremento atomico .
- All'uscita dal metodo, il
shared_ptrparametro 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_ptrparametro per valore e poi std::moveall'interno del metodo (come correttamente fatto nel codice di Clang), hai:
- Quando si immette il metodo, il
shared_ptrparametro viene creato come copia: incremento del conteggio atomico .
- All'interno del corpo del metodo, è
std::moveil shared_ptrparametro 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_ptrparametro viene distrutto; ma poiché ti sei spostato nel passaggio 2, non c'è nulla da distruggere, poiché il shared_ptrparametro 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.