Переміщення операцій (наприклад , переміщення конструктора) для std::shared_ptr
є дешевим , так як вони в основному є «викрадення покажчики» (від джерела до пункту призначення, дозволяючи бути більш точним, то весь блок державного управління «вкрадено» від джерела до місця призначення, в тому числі інформації підрахунку посилань) .
Натомість операції копіювання на std::shared_ptr
виклику атомного опорного числа збільшуються (тобто не лише ++RefCount
на цілий RefCount
член даних, але, наприклад, виклик InterlockedIncrement
в Windows), що дорожче, ніж просто крадіжка покажчиків / стану.
Отже, детально аналізуючи динаміку підрахунку посилань:
// shared_ptr<CompilerInvocation> sp;
compilerInstance.setInvocation(sp);
Якщо ви переходите sp
за значенням, а потім робите копію всередині CompilerInstance::setInvocation
методу, у вас є:
- При введенні методу
shared_ptr
параметр будується копією: збільшення числа атомних приростів .
- Усередині тіла методу, ви скопіювати в
shared_ptr
параметр в елементі даних: ЗАВДАННЯ розраховувати атомне приріст .
- При виході з методу
shared_ptr
руйнується параметр: атомний декремент .
У вас є два атомних прирости і один атомний декремент, в цілому три атомні операції.
Натомість, якщо ви передаєте shared_ptr
параметр за значенням, а потім std::move
всередині методу (як це правильно зроблено в коді Кланг), у вас є:
- При введенні методу
shared_ptr
параметр будується копією: збільшення числа атомних приростів .
- Усередині тіла методу, ви параметр в елемент даних: вих лічильник нічого НЕ зміниться! Ви просто крадете вказівники / стан: жодних дорогих операцій підрахунку атомних змін не задіяно.
std::move
shared_ptr
- При виході з методу
shared_ptr
параметр руйнується; але оскільки ви перейшли на крок 2, нічого руйнувати не можна, оскільки shared_ptr
параметр більше не вказує ні на що. Знову-таки, ніякого атомного декременту в цьому випадку не відбувається.
Підсумок: у цьому випадку ви отримуєте лише один приріст атомного приросту, тобто лише одну атомну операцію.
Як бачите, це набагато краще, ніж два атомних кроки плюс один атомний декремент (для загальних трьох атомних операцій) для випадку копіювання.