Присвоение через копирование и обмен в сравнении с двумя блокировками

Заимствовав пример Ховарда Хиннанта и изменив его для использования копирования и обмена, это op = потокобезопасный?

struct A {
  A() = default;
  A(A const &x);  // Assume implements correct locking and copying.

  A& operator=(A x) {
    std::lock_guard lock_data (_mut);
    using std::swap;
    swap(_data, x._data);
    return *this;
  }

private:
  mutable std::mutex _mut;
  std::vector _data;
};

Я считаю, что это потокобезопасный (помните op = 's параметр передается по значению), и единственная проблема, которую я могу найти, - это та, которая скрыта под ковриком: копия ctor. Однако это будет редкий класс, который допускает копирование-присваивание, но не копирование-конструирование, так что эта проблема существует в равной степени в обеих альтернативах.

Учитывая, что самоназначение настолько редкое (по крайней мере, для этого примера), что я не Не обращайте внимания на лишнюю копию, если это произойдет, считайте потенциальную оптимизацию этого! = & rhs либо незначительной, либо пессимизацией. Будет ли какая-то другая причина предпочитать или избегать ее по сравнению с исходной стратегией (ниже)?

A& operator=(A const &rhs) {
  if (this != &rhs) {
    std::unique_lock lhs_lock(    _mut, std::defer_lock);
    std::unique_lock rhs_lock(rhs._mut, std::defer_lock);
    std::lock(lhs_lock, rhs_lock);
    _data = rhs._data;
  }
  return *this;
}

Между прочим, я думаю, что это лаконично обрабатывает ctor копирования, по крайней мере для этого класса, даже если это немного глупо:

A(A const &x) : _data {(std::lock_guard(x._mut), x._data)} {}

]

6
задан Fred Nurk 30 May 2011 в 19:05
поделиться