Подтвердить что ты не робот

Почему std:: lock_guard не движется?

Почему std:: lock_guard не движется, это сделает код намного приятнее:

auto locked = lock_guard(mutex);

вместо

std::lock_guard<std::mutex> locked(mutex);

Что-то не так с созданием вашей собственной версии, например:

template <typename T> class lock_guard_
{
  T* Mutex_;
  lock_guard_(const lock_guard_&) = delete;
  lock_guard_& operator=(const lock_guard_&) = delete;
public:
  lock_guard_(T& mutex) : Mutex_(&mutex)
  {
    Mutex_->lock();
  }
  ~lock_guard_()
  {
    if(Mutex_!=nullptr)
      Mutex_->unlock();
  }
  lock_guard_(lock_guard_&& guard)
  {
    Mutex_ = guard.Mutex_;
    guard.Mutex_ = nullptr;
  }
};

template <typename T> lock_guard_<T> lock_guard(T& mutex)
{
  return lock_guard_<T>(mutex);
}

?

Любая фундаментальная причина было бы плохой идеей сделать ее подвижной?

4b9b3361

Ответ 1

lock_guard всегда задействован; он всегда ссылается на мьютекс и всегда разблокирует его в своем деструкторе. Если он был подвижным, ему нужно было бы удерживать указатель вместо ссылки и проверять указатель в его деструкторе. Это может показаться тривиальной ценой, но философия С++ не платит за то, что вы не используете.

Если вы хотите передвижную (и освобождаемую) блокировку, вы можете использовать unique_lock.

Вам может быть интересно n3602 Вывод параметров шаблона для конструкторов, что устраняет необходимость в функциях make_. Это не будет в С++ 14, но мы можем надеяться на С++ 17.

Ответ 2

Вы можете сделать:

auto&& g = std::lock_guard<std::mutex> { mutex };

Очевидно, что это не совсем удовлетворительно, поскольку это не приводит к вычету. Ваша попытка вывести factory почти там, за исключением того, что вам нужно использовать инициализацию списка для возврата недвижного объекта:

template<typename Mutex>
std::lock_guard<Mutex> lock_guard(Mutex& mutex)
{
    mutex.lock();
    return { mutex, std::adopt_lock };
}

который позволяет auto&& g = lock_guard(mutex);.

(Неловкий танец с std::adopt_lock обусловлен тем, что унарный конструктор является явным. Поэтому мы не можем сделать return { mutex };, поскольку это запрещенное преобразование, тогда как return std::lock_guard<Mutex> { mutex }; выполняет инициализацию списка временного, которое мы не можем переместить в возвращаемое значение.)