
On Aug 27, 2007, at 12:13 AM, Gottlob Frege wrote:
a unique_lock references an objet, and has exclusive ownership of its locked state. Slightly different. And 'ref' != 'own'. Or 'own' is ambiguous between owning the object and owning the state of the object.
Not disagreeing with you at all. Below is my attempt at a clarification of the difference between referencing a mutex, and holding the lock on the mutex, and how the current syntax and semantics behaves with respect to those two states. Hopefully what is below *is* a clarification, and not further confusion. In the current syntax: A unique_lock<Mutex> lk; references a mutex if: lk.mutex() != 0 and owns/holds the lock if: lk.owns() == true An invariant is that if the lock does not reference a mutex: lk.mutex() == 0 then lk.owns() will be false. The rationale for allowing lk.mutex() to become null is two-fold: 1. A unique_lock default constructor could be handy, say for new'ing an array of unique_lock. One can always move assign a default constructed unique_lock to give it a reference to a mutex: mutex mut; unique_lock<mutex> lk; assert(lk.mutex() == 0); assert(!lk.owns()); lk = unique_lock<mutex>(mut); assert(lk.mutex() != 0); assert(lk.owns()); unique_lock<mutex> other(std::move(lk)); assert(lk.mutex() == 0); assert(!lk.owns()); 2. A move construct, and move assign from a unique_lock leaves the source referencing no mutex. We could have left the source referencing the mutex, but just not owning the lock. However that would be slightly more error prone. For example: void bar(unique_lock<mutex> lk); // bar accepts lock ownership void foo() { unique_lock<mutex> lk(mut, defer_lock); // Normally when you can assert that // you are referencing a mutex *and* // you do not own the locked state of the mutex, then... assert(lk.mutex() != 0) assert(!lk.owns()); // ... it is safe to lock: lk.lock(); // However if move construction did not drop the reference ... bar(move(lk)); // ... then the following asserts would both be true but assert(lk.mutex() != 0) assert(!lk.owns()); // ... locking the lock is no longer safe lk.lock(); // probable error // This thread may still own the lock on mut. // bar() could have passed ownership to a global, // or to some object member data. // Therefore it is best if ... assert(lk.mutex() == 0); // ... after the call to bar() } -Howard