Почему 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);
}
?
Любая фундаментальная причина было бы плохой идеей сделать ее подвижной?
Ответы
Ответ 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 };
выполняет инициализацию списка временного, которое мы не можем переместить в возвращаемое значение.)