Discussion: `std::optional<std::reference_wrapper<T>>` seem to be error prone
Dear all,
I would like to start a discussion on our use of std::optional<std::reference_wrapper<T>>
.
At first glance, the construct seems to offer almost exactly the same functionality as a raw pointer:
- The
std::optional
may be false, just as a raw pointer may be null - The
std::reference_wrapper
wraps a reference, which essentially is a pointer that cannot be null - The
std::reference_wrapper
may be rebound, just as a raw pointer
However, I believe that the construct conveys a false sense of safety.
- It is a copyable value type that invites to be "saved for later use"
- The
std::optional
may be tested for "validity", but says nothing about the validity of the referenced object - The referenced object may still be deleted, without the construct's knowing
In fact, I would argue that with raw pointers, at least the users would intuitively know about these dangers. The construct however, being somewhat unfamiliar, seems to hide some of these dangers while doing nothing to improve safe usage.
To my knowledge, the Standard Libray provides only one construct that can provide a reference to an object, that can be repeatedly tested for the validity of the referenced object: std::weak_ptr
.
This comes, of course, at the price of some runtime cost.
Also, std::weak_ptr::lock
temporarily takes (shared) ownership of the referenced object, which may not be desirable.
Returning a std::weak_ptr
from a function however conveys (to me at least) that I may borrow temporary ownership, but that I should hold onto said ownership as least as possible.
Sadly, there exists no std::weak_ptr
equivalent for std::unique_ptr
in the Standard Library.
Since this is a known gap in the library, there exist some FOSS implementations and proposals:
-
SaferCPlusPlus Registered Pointers
"Registered" pointers behave much like native C++ pointers, except that their value is (automatically) set to nullptr when the target object is destroyed. And by default they will throw an exception upon any attempt to dereference a nullptr. Because they don't take ownership like some other smart pointers, they can point to objects allocated on the stack as well as the heap.
-
Library fundamentals v2 std::experimental::observer_ptr
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.
Looking forward to your thoughts on the matter.
Cheers, Martin