Эффективность копирования и обмена для общих указателей
Это можно рассматривать как продолжение, например. Почему присвоение общего указателя делает "своп"?,
Вопрос об идиоме Copy&Swap, используемой, например, в boost.
Я понимаю, что преимущество Copy&Swap заключается в повторном использовании существующего кода, что позволяет избежать дублирования и ошибок. Но есть 2 случая (фактически 1 может быть уменьшен до другого), где это не оптимально:
- Экземпляры умного указателя совпадают
- Содержащийся указатель такой же
За shared_ptr
счетчики ссылок увеличиваются атомарно и для intrusive_ptr
(только буст) они могут быть. Таким образом, существует высокая стоимость за копию.
Этого можно избежать, если назначение было реализовано так:
smart_ptr& operator=(const smart_ptr& other){
if(this->ptr_ == other.ptr_) return *this;
smart_ptr(other).swap(*this); // I assume I can simply do this here, right?
return *this;
}
smart_ptr& operator=(smart_ptr&& other){
smart_ptr(std::move(other)).swap(*this);
return *this;
}
Разве это не было бы самой быстрой и безопасной реализацией или есть какая-то проблема, которую я не видел?
Если он самый быстрый, то почему его не используют boost или stdlib?
Чтобы уточнить пункт 2. рассмотрим следующий код:
smart_ptr a(new foo);
auto b = a;
...
// Eventually:
a = b;
Это не самоопределение как &a != &b
, Копирование и обмен действительно включают в себя ненужную модификацию счетчика ссылок.
1 ответ
Самостоятельное назначение не является распространенным случаем, поэтому каждый раз стоит проверять это, а не менять его в любом случае. Кроме того, копирование указателя является в основном самой быстрой копией, которую можно выполнить.
Реальная стоимость копирования shared_ptr - это атомарный инкремент ссылки (который может включать использование мьютекса внизу).
Если вы действительно хотите протестировать производительность обоих подходов, я бы порекомендовал получить библиотеку бенчмарков Google и написать набор тестовых случаев (для самостоятельного задания и всех других случаев) и измерить его. Помните, что оптимизатор в наши дни может удивить ваш код, чтобы оптимизировать его. Без его измерения было бы трудно сказать, быстрее ли это, но я думаю, что как бы довольно дорогая версия без нее лучше:)
РЕДАКТИРОВАТЬ:
Если вы не хотите увеличивать счетчик ссылок (это дорогостоящая часть с копированием shared_ptr), вы всегда можете использовать конструктор перемещения:
smart_ptr a(new foo);
auto b = a;
...
// Eventually:
a = std::move(b);