It occurred to me that in C++ it is possible to use the type std::optional<std::reference_wrapper<T>>
. An object of this type is essentially a reference to an object of type T
or a null value, i.e., pretty much a pointer. My questions:
Is there any conceptual difference between std::optional<std::reference_wrapper<T>>
and T*
?
Is there any practical difference? Are there situations where it might be advisable to choose std::optional<std::reference_wrapper<T>>
over T*
?
In a word, optional references share some semantics with pointers: they can point to something like a normal reference, and they can also point to nothing when they're a null optional. But they only represent handles and don't do pointer arithmetics and such low-level features.
A reference_wrapper can be used to store references in standard containers, and to pass objects by reference to std::bind . The type Ty must be an object type or a function type, or a static assert fails at compile time. The helper functions std::ref and std::cref can be used to create reference_wrapper objects.
Thus, an optional object models an object, not a pointer, even though operator*() and operator->() are defined. When an object of type optional<T> is contextually converted to bool , the conversion returns true if the object contains a value and false if it does not contain a value.
What's more, std::optional doesn't need to allocate any memory on the free store. std::optional is a part of C++ vocabulary types along with std::any , std::variant and std::string_view .
Is there any conceptual difference between
std::optional<std::reference_wrapper<T>>
andT*
?
std::optional<>
, as the name already suggest, is meant to be used when we could have a value or might not have any value at all.
The equivalent of having no value for a T*
object would be assigning nullptr
to it, i.e.: the pointer will point to nowhere, as opposed to somewhere (or even anywhere, i.e.: uninitialized). It can be said that std::optional<>
exports the concept of nullptr
for pointers to any arbitrary type. So, I would say they are conceptually very similar, being the std::option<>
approach a kind of generalization.
Is there any practical difference? Are there situations where it might be advisable to choose
std::optional<std::reference_wrapper<T>>
overT*
?
I can think of the size. std::optional<>
contains an internal flag for indicating the presence/absence of a value, whereas for T*
the nullptr
is encoded directly as one of the values the pointer can store. So a std::optional<std::reference_wrapper<T>>
object will be larger than a T*
.
When it comes to safety, unlike T*
, std::optional<>
provides the member function value()
which throws an exception if there is no value (it provides as well as the unsafe operator*()
as T*
does).
Also, using std::optional<std::reference_wrapper<T>>
instead of T*
, for example, as a function's return value may indicate in a more explicit way that there might be no value at all.
The main difference between std::optional<std::reference_wrapper<T>>
and T*
is that with T*
you have to think about who owns the memory that is pointed to.
If a function returns T*
you have to know if you are responsible for freeing the memory or someone else is. That's not something you have to be concerned with when it's a reference.
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