почему 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);
}

?

По какой-то фундаментальной причине было бы плохой идеей сделать его подвижным?

19

Решение

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

Если вы хотите подвижный (и съемный) замок, вы можете использовать unique_lock,

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

16

Другие решения

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

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

10

По вопросам рекламы [email protected]