The following code:
std::optional<std::string> so;
std::cout << so->size() << std::endl;
std::cout << so.has_value();
outputs:
0
0
My question is whether its safe to call : so->size()
on an empty optional. I used clang sanitizer, but it didnt report any UB in above code.
A common use case for optional is the return value of a function that may fail. As opposed to other approaches, such as std::pair<T,bool>, optional handles expensive-to-construct objects well and is more readable, as the intent is expressed explicitly.
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 .
C++17 introduced std::optional<T> which lets you augment the values of a type T with a bonus value known as std::nullopt which semantically represents the absence of a value. A std::optional which holds the value std::nullopt is known as empty.
Using operator->
on an empty std::optional
is Undefined Behavior, regardless of what type T
is in std::optional<T>
.
According to cppreference on std::optional<T>::operator->
:
The behavior is undefined if
*this
does not contain a value.
Quoting the current C++ working draft
20.6.3.6 Observers [optional.observe]
constexpr const T* operator->() const;
constexpr T* operator->();
Preconditions: *this contains a value.
Then:
16.3.2.4 Detailed specifications [structure.specifications]
Preconditions: the conditions that the function assumes to hold whenever it is called; violation of any preconditions results in undefined behavior.
Thus, it's undefined behavior.
You're calling the default optional
constructor (1 in that link), which...
- Constructs an object that does not contain a value.
When you go to dereference...
The behavior is undefined if *this does not contain a value.
Which in your case it doesn't. So yes, you have UB.
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