Эффективность копирования и обмена для общих указателей

Это можно рассматривать как продолжение, например. Почему присвоение общего указателя делает "своп"?,

Вопрос об идиоме Copy&Swap, используемой, например, в boost.

Я понимаю, что преимущество Copy&Swap заключается в повторном использовании существующего кода, что позволяет избежать дублирования и ошибок. Но есть 2 случая (фактически 1 может быть уменьшен до другого), где это не оптимально:

  1. Экземпляры умного указателя совпадают
  2. Содержащийся указатель такой же

За 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);
Другие вопросы по тегам