It could be implemented thusly:
std::shared_ptr<T> operator->() {
auto shared = lock();
if(shared == nullptr) {
throw std::bad_weak_ptr(); // or some other exception
}
return shared;
}
Live Demo
Why did the authors of weak_ptr decide to not have operator->? (They must have thought of it)
I can think of potential reasons but I wonder what the official reason is, if one exists. Potential reasons:
If you are confused about the lifetime of the returned shared_ptr, see this paper.
Also, someone asked why would one use a weak_ptr if you expect it to not be expired? Answer: cycles.
std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.
By using a weak_ptr , you can create a shared_ptr that joins to an existing set of related instances, but only if the underlying memory resource is still valid. A weak_ptr itself does not participate in the reference counting, and therefore, it cannot prevent the reference count from going to zero.
Note that the control block used by std::weak_ptr and std::shared_ptr is thread-safe: different non-atomic std::weak_ptr objects can be accessed using mutable operations, such as operator= or reset , simultaneously by multiple threads, even when these instances are copies or otherwise share the same control block ...
To implement weak_ptr , the "counter" object stores two different counters: The "use count" is the number of shared_ptr instances pointing to the object. The "weak count" is the number of weak_ptr instances pointing to the object, plus one if the "use count" is still > 0.
The original proposal weak_ptr
didn't include an overload of operator->
.
I haven't looked through the minutes of every meeting since, but have followed what's been discussed, and don't recall a mention of anybody having proposed that it should be added. As such, the "official" reason it's not present is probably largely that nobody's proposed that it be added.
If you want to go back to the very beginning, most of this stems from John Ellis and David Detlef's Safe, Efficient Garbage Collection for C++ paper, from Usenix 1994. That included a weakptr
type in its Appendix B. That's somewhat different (weakptr::pointer
returns a pointer directly, or a null-pointer if the pointee has already been destroyed), but still didn't use an operator overload to do the job.
Greg Colvin wrote the original proposal to add counted_ptr
to the standard. Its counted_ptr
was essentially equivalent to what's now called shared_ptr
, but did not include anything analogous to weak_ptr
.
Shortly after the committee rejected the counted_ptr
proposal and adopted auto_ptr
instead, the basic idea of counted_ptr
was revived on Boost. I don't remember seeing any discussion of adding an operator->
to it, but it "lived" there for so long that it's entirely possible somebody could have proposed it without my being aware of it.
I'll take a shot at giving a good reason why this is not a good idea:
One thing is clarity:
ptr->foo();
ptr->bar();
The problem here is that somewhere between the first and second call, ptr might expire, either by a different thread (which would be a race condition) or by a sideeffect of the call to foo
.
Another thing is symmetry: When I have a pointer, I expect operators *
, ->
and an implicit conversion to a boolean value. Some might disagree, but operators *
and ->
often coincide. I'd be surprised that this isn't the case here.
That said, with C++11, it's just too easy to write:
if (auto p = ptr.lock()) {
p->foo();
p->bar();
}
Knowing that ptr
is a weak_ptr
, the meaning and behaviour of that code is pretty clear.
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