
On Dec 18, 2007, at 1:24 PM, Frank Mori Hess wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Tuesday 18 December 2007 11:48 am, Howard Hinnant wrote:
That being said, a non-movable boost::mutex does not prohibit a wrapper around that type from being movable, if you're willing to accept alternative semantics. I'm not familiar with the boost move library, but the C++0X syntax would simply be:
class my_wrapper { std::mutex mut_; // or boost::mutex public: my_wrapper() {} my_wrapper(my_wrapper&&) {} // same as default ctor my_wrapper& operator=(my_wrapper&&) {return *this;} // do nothing
void lock() {mut_.lock();} bool try_lock() {return mut_.try_lock();} void unlock() {mut_.unlock();} };
What I'm thinking of is more along the lines of
template<typename Mutex> class my_wrapper { Mutex mut_; public: my_wrapper(Mutex &&mut): mut_(mut); // ... };
So I can have a my_wrapper<Mutex> without worrying about whether the template Mutex type has some weird constructor, or even if it is default constructible. I guess the best I could do along those lines is to have a constructor that allows the user to pass in a dynamically allocated Mutex, which the wrapper would take ownership of. Note, I've never really done anything with rvalue references or moveable types, so maybe this is an abuse of them?
This sort of sounds like the proposed std::unique_lock<Mutex> (which Anthony has generously prototyped on the boost trunk): http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2447.htm#MutexsLock... template <class Mutex> class unique_lock { public: typedef Mutex mutex_type; private: mutex_type* m_; bool owns_lock_; unique_lock(unique_lock const&) = delete; unique_lock& operator=(unique_lock const&) = delete; public: ... explicit unique_lock(mutex_type& m) : m_(&m), owns_lock_(true) { m_->lock(); } ... ~unique_lock() { if (owns_lock_) m_->unlock(); } unique_lock(unique_lock&& u) // transfers mutex lock ownership to this : m_(u.m_), owns_lock_(u.owns_lock_) { u.m_ = 0; u.owns_lock_ = false; } unique_lock& operator=(unique_lock&& u) // transfers mutex lock ownership to this { if (owns_lock_) m_->unlock(); owns_lock_ = u.owns_lock_; m_ = u.m_; u.owns_lock_ = false; u.m_ = 0; return *this; } void lock(); bool try_lock(); ... }; This is slightly differs from what you suggest in that the lifetime of the Mutex isn't managed, but only the lock ownership. But the "wrapper" is moveable. Use cases might look like: std::mutex mut; // mutex constructed and destructed with static storage duration std::unique_lock<std::mutex> get_a_lock() { // might do something more complex in here besides // simply returning the lock return std::unique_lock<std::mutex>(mut); // lock mut and return a wrapper to it } void foo() { std::unique_lock<std::mutex> the_lock = get_a_lock(); // movable lock allows returning from factory function // mut locked in here } // mut unlocked here Some of this is C++0X, like the ability to return movable but non- copyable items from factory functions. Is this getting close to what you were wanting to do? -Howard