Почему 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);
}
?
По какой-то фундаментальной причине было бы плохой идеей сделать его подвижным?
lock_guard
является всегда занимается; он всегда содержит ссылку на мьютекс и всегда разблокирует его в деструкторе. Если бы он был подвижным, он должен был бы держать указатель вместо ссылки и проверять указатель в его деструкторе. Это может показаться тривиальной ценой, но философия C ++ заключается в том, что вы не платите за то, что не используете.
Если вы хотите подвижный (и съемный) замок, вы можете использовать unique_lock
,
Вы можете быть заинтересованы в n3602 Вывод параметров шаблона для конструкторов, что устраняет необходимость make_
функции. Это не будет в C ++ 14, но мы можем надеяться на C ++ 17.
Ты можешь сделать:
auto&& g = std::lock_guard<std::mutex> { mutex };
Очевидно, что это не совсем удовлетворительно, так как это не приводит к выводу. Ваша попытка получить фабрику вывода почти готова, за исключением того факта, что вам нужно использовать инициализацию списка для возврата неподвижного объекта:
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 };
выполняет инициализацию списка для временного объекта, который мы не можем затем переместить в возвращаемое значение.)