
Howard Hinnant wrote:
On Mar 22, 2007, at 1:14 PM, Yuval Ronen wrote:
The usual idiom is to have the mutex at namespace scope, or as a class data member, and have the lock referring to that mutex "on the stack". So for the usual idioms, non-copyable, non-movable mutexes do not seem overly problematic. I'm not sure it's not problematic. If the mutex is class data member (a very common scenario - perhaps the most common one), then it makes that class non-movable. Non-copyable - I understand, but non-movable - that's a major limitation, IMO.
I think we're ok here, both for copying and moving. Here's a prototype class A which owns an int on the heap. And because I think this is a cool use of the read/write locks from N2094 I'm going to use them to implement the copy assignment. :-)
I'm typing this code in untested, so please forgive me any careless mistakes.
class A { int* the_data_; std::sharable_mutex mut_;
typedef std::sharable_lock<std::sharable_mutex> read_lock; typedef std::exclusive_lock<std::sharable_mutex> write_lock; public: explicit A(int data) : the_data_(new int(data)) {} ~A() {delete the_data_;}
// copy semantics A(const A& a) : the_data_(0) { read_lock lk(a.mut_); if (a.the_data_ != 0) the_data_ = new int(*a.the_data_); } A& operator=(const A& a) { if (this != &a) { read_lock lock_a(a.mut_, std::defer_lock); write_lock lock_this(mut_, std::defer_lock); std::lock(lock_this, lock_a); // prevents deadlock int* new_data = a.the_data_ ? new int(*a.the_data_) : (int*)0; delete the_data_; the_data_ = new_data; } return *this; }
// move semantics A(A&& a) : the_data_(a.the_data_) { a.the_data_ = 0; // no locking required, a is an rvalue! :-) } A& operator=(A&& a) { write_lock lock_this(mut_); delete the_data_; the_data_ = a.the_data_; a.the_data_ = 0; return *this; } };
I.e. you just move or copy the protected data and not the mutex.
The main thing I was thinking about is the move constructor. Instead of stealing the mutex from the rvalue, you construct a new mutex, and let the old one be destructed. This might be not optimal. But on the other hand, it might not be that bad after all, I don't know...