Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of observer_ptr

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?

like image 725
RamblingMad Avatar asked Aug 06 '15 17:08

RamblingMad


2 Answers

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.

like image 187
Barry Avatar answered Oct 05 '22 08:10

Barry


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.

like image 38
Galik Avatar answered Oct 05 '22 07:10

Galik