a weak_ptr can be said to have three states.
1. Never been assigned to (default constructed) 2. Assigned to, lock will return a shared_ptr to a valid object. 3. Assigned to, but the object pointed to is dead and lock will return null.
There is no particular reason to make 1 and 3 indistinguishable. You are right that weak_ptr could have provided an "is empty" query in addition to expired(). There just aren't any compelling use cases for it, as far as I know.
Are there compelling reasons not to add such a member function, i.e. a different shared_ptr implementation wouldn't be able to provide such a function? A friend of mine actually came up with a use case in his code, which is what prompted this question. In pseudo-code, it looked like this: struct guarded_memory { void* memory; weak_ptr guard; guarded_memory(void* m) : guard(), memory(m) {} guarded_memory(void* m, weak_ptr g) : guard(g), memory(m) {} void access() { if (guard.never_been_assigned_to_before()) { // no guard means always accessible do_something_with(memory); } else { if (shared_ptr p = guard.lock()) { do_something_with(memory); } } } }; Basically; if the user never provided a guard, the memory is deemed accesible at all times, otherwise accessibility depends on the liveliness of the pointed to guard. In my opinion, the code is ackwardly assymetrical and not an example of great design, but alas, it's what he came up with in some context. The solution to the above code is too add a litle boolean that remembers which of the two constructors has been called. This boolean is strictly speaking redundant because weak_ptr already stores this information. Hence my question. Thanks, Jaap Suter