Why is std::lock_guard
not movable, it would make code so much nicer:
auto locked = lock_guard(mutex);
instead of
std::lock_guard<std::mutex> locked(mutex);
Is there something wrong with creating your own version, like:
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);
}
?
Any fundamental reason it would be a bad idea to make it movable?
std::lock_guard A lock guard is an object that manages a mutex object by keeping it always locked. On construction, the mutex object is locked by the calling thread, and on destruction, the mutex is unlocked.
And that's why lock_guard isn't deprecated. scoped_lock and unique_lock may be a superset of functionality of lock_guard , but that fact is a double-edged sword. Sometimes it is just as important what a type won't do (default construct in this case).
lock_guard
is always engaged; it always holds a reference to a mutex and always unlocks it in its destructor. If it was movable then it would need to hold a pointer instead of a reference, and test the pointer in its destructor. This might seem a trivial cost, but it is C++ philosophy that you don't pay for what you don't use.
If you want a movable (and releaseable) lock you can use unique_lock
.
You might be interested in n3602 Template parameter deduction for constructors, which removes the need for make_
functions. It won't be in C++14 but we can hope for C++17.
You can do:
auto&& g = std::lock_guard<std::mutex> { mutex };
Obviously this isn’t entirely satisfactory as this performs no deduction. Your attempt at a deducing factory is almost there save for the fact that you need to use list-initialization to return a non-movable object:
template<typename Mutex>
std::lock_guard<Mutex> lock_guard(Mutex& mutex)
{
mutex.lock();
return { mutex, std::adopt_lock };
}
which allows for auto&& g = lock_guard(mutex);
.
(The awkward dance with std::adopt_lock
is due to the unary constructor being explicit. So we can’t do return { mutex };
as that’s a disallowed conversion, while return std::lock_guard<Mutex> { mutex };
performs list-initialization of a temporary — which we can’t then move into the return value.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With