What exactly is the point of the construct std::observer_ptr
in the library fundamentals technical specification V2?
It seems to me that all it does is wrap a bare T*
, which seems like a superfluous step if it adds no dynamic memory safety.
In all of my code I use std::unique_ptr
where I need to take explicit ownership of an object and std::shared_ptr
where I can share ownership of an object.
This works very well and prevents accidental dereferencing of an already destroyed object.
std::observer_ptr
makes no guarantee about the lifetime of the object observed, of course.
If it were to be constructed from a std::unique_ptr
or std::shared_ptr
I would see a use in such a structure, but any code that is simply using T*
is probably just going to keep doing so and if they plan on moving to anything it would be std::shared_ptr
and/or std::unique_ptr
(depending on use).
Given a simple example function:
template<typename T> auto func(std::observer_ptr<T> ptr){}
Where it would be useful if it stopped smart pointers from destroying their stored object while they are being observed.
But if I want to observe a std::shared_ptr
or std::unique_ptr
I have to write:
auto main() -> int{ auto uptr = std::make_unique<int>(5); auto sptr = std::make_shared<int>(6); func(uptr.get()); func(sptr.get()); }
Which makes it no safer than:
template<typename T> auto func(T *ptr){}
So, what is the use of this new structure?
Is it just for self-documenting source?
The proposal makes it pretty clear that it's just for self-documentation:
This paper proposes
observer_ptr
, a (not very) smart pointer type that takes no ownership responsibility for its pointees, i.e., for the objects it observes. As such, it is intended as a near drop-in replacement for raw pointer types, with the advantage that, as a vocabulary type, it indicates its intended use without need for detailed analysis by code readers.
When you need shared access but not shared ownership.
The problem is that raw pointers are still very useful and have perfectly respectable use-case scenarios.
When a raw pointer is managed by a smart pointer its cleanup is guaranteed and so, within the lifespan of the smart pointer, it makes sense to access the actual data through the raw pointer that the smart pointer is managing.
So when we create functions, that would normally take a raw pointer, a good way of promising that the function will not delete that pointer is to use a strongly typed class like std::observer_ptr
.
When passing a managed raw pointer as an argument to a std::observer_ptr
function parameter, we know that the function is not going to delete
it.
It is a way for a function to say "give me your pointer, I will not meddle with its allocation, I will just use it to observe".
Incidentally I'm not keen on the name std::observer_ptr
because that implies you can look but not touch. But that is not really true. I would have gone with something more like access_ptr
.
Additional note:
This is a different use-case from a std::shared_ptr
. The std::shared_ptr
is about sharing ownership and it should only be used when you can not determine which owning object will go out of scope first.
The std::observer_ptr
, on the other hand, is for when you want to share access but not ownership.
It is not really appropriate to use std::shared_ptr
simply to share access because that could be very inefficient.
So, whether you are managing your target pointer using a std::unique_ptr
or a std::shared_ptr
there is still a use-case for raw-pointers and hence the rational for a std::observer_ptr
.
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