Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use std::optional as a regular pointer vs use has_value() and value

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.

like image 809
Gordon Tseng Avatar asked May 10 '19 17:05

Gordon Tseng


People also ask

What is STD optional and how to use it?

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."

Is an optional an object or a pointer?

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?

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.

What is an optional value in C++?

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.


2 Answers

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.

like image 94
Barry Avatar answered Oct 19 '22 23:10

Barry


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();
like image 34
SergeyA Avatar answered Oct 19 '22 22:10

SergeyA