std::optional
can use the syntax to access its value similar to a normal pointer, like .
std::optional<string> some_str;
if (some_str)
(*some_str).c_str();
but it also has two functions, has_value()
and value()
to provide access to its value and to check if the value exists.
std::optional<string> some_str;
if (some_str.has_value())
some_str.value().c_str();
I am wondering what is the difference between these two
Is it for?
1. more verbose
2. performance?
3. better logging and debugging? value()
will throw exception.
In this article, I'll describe std:optional — a new helper type added in C++17. It's a wrapper for your type and a flag that indicates if the value is initialized or not. Let's see where it can be useful and how you can use it. By adding the boolean flag to other types, you can achieve a thing called "nullable types."
If an optional<T> contains a value, the value is guaranteed to be allocated as part of the optional object footprint, i.e. no dynamic memory allocation ever takes place. Thus, an optional object models an object, not a pointer, even though operator* () and operator-> () are defined.
Is std::optional<T&> the same as a pointer? What does it even mean to have an “optional T& ”? Well, it is a T& that can also be nullptr. So a pointer, a T*? No, not really. There is a more important difference between T& and T* besides the nullability: A T& has implicit creation and access, a T* explicit creation and access.
std::optional The class template std::optional manages an optional contained value, i.e. a value that may or may not be present. A common use case for optional is the return value of a function that may fail.
There are two separate things here.
First, explicit operator bool() const
vs bool has_value() const
. These are exactly synonyms. They mean the exact same thing. Use whichever one you prefer.
Second, T& value()
vs T& operator*()
. This is the same as vector::at
vs. vector::operator[]
. The former has no preconditions - it checks and throws - the latter has preconditions - it is undefined behavior if the optional is disengaged.
std::optional
(no experimental, C++17 is upon us) defines two different interfaces to access it's optional member: the checked access (std::optional::value
) and the unchecked access (operator*
).
Using checked access has two potential drawbacks - first, it slows execution down because branch is executed, and second, in case of value not being there it will throw an exception, which could be undesirable in terms of control flow. While the second issue can be alleviated via explicit check for value present (std::optional::has_value
) before calling value, the run-time performance cost could still be there.
An unchecked access doesn't have performance cost associated to that, but can only be safely used if you know that the value is there by some other means (i.e. you checked has_value
before). Otherwise, behavior of the program is undefined, and we do not want that.
From the above, it should be obvious that the second snippet you have shown is excessive:
if (some_str.has_value())
some_str.value().c_str();
Does the check for value presence twice (at least semantically, compilers are likely to be able to optimize the second check away). Still, the clearer code would be
if (some_str.has_value())
some_str->c_str();
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