Weekly C++ 14 – std::optional

Hello, my friends, we are together with another weekly C++ post. The topic of this post is about std::optional which is introduced with C++ 17. In this post, we are going to take alook at why we need such capability an in which cases we can use that with example codes. This post will be followed by std::variant and std::any topics which are also related with this topic.

person holding light bulb

First of all, let us look at why we need such feature. I am sure, at one point in your code, you needed to state whether a given variable contains value or not (i.e. middle names or optional arguments provided via command line). Of course, there are solutions that can be used to deal with this problem. For instance, for pointers, you may use nullptr to state but it still does not give much information about whether given pointer is not allocated or does not contain any valid value, right? This is a little bit different for other types. -1 or similar values can be used for integral values, but in that case, -1 can not be used  anymore. It may also not be possible to come up with such numbers or not suitable (i.e. for floating numbers). Besides, in those cases, you usually required to perform additional checks.

std::optional, is introduced to resolve such issues. With this feature, we are able to check if a value is available or not in a more standard and expressive manner. Such types are also known as nullable typesin some references. Similarly, this can be used for returning values and passing parameters to functions which may or may not be available.

Most of the std::optional features are based on boost::optional, so if you are familiar with that library, you can easily adapt std::optional in your codes (by the way I have added an example reference for boost::optional usage). To use std::optional, you need to add #include <optional> header file. std::optional does not allocate memory from heap, in fact, it is simply a wrapper around the type provided. At most, one additional byte is allocated to specify availability.

So, afterall, in which cases we should use this feature? Good question. Let us look at a part of explanation given in boost::optional page, to see the full description you can check out this page.:

It is recommended to use optional<T> in situations where there is exactly one, clear (to all parties) reason for having no value of type T, and where the lack of value is as natural as having any regular value of T.

You can use std::optional as class member, return value or parameter that will be passed to functions. Before delving into details and other examples, let us look at a simple example code that uses std::optional for a function that convert (if possible) string to integer:

Now, let us go over individual capabilities of std::optional usage one by one with example source code snippets. Later, we will look at complete code examples:

  • At any time, an instance of optional<T> may either contain a T value or does not contain any value at all which is express with std::nullopt (type of std::nullopt_t).
  • How can we create an instance of optional<T>?
    • We can create std::optional instances that do not contain any values as follows. Both of following instances do not contain any value and no contructor is called:

    • We can create std::optional instances with given values or instances as follow. std::optional can also deduce types from provided parameters:

    • The instances that require multiple parameters, can be separately created and passed to std::optional instances which may cause temporary copy operations. The std::optional instances can directly be created with given multiple parameters (like emplace_back in STL containers) which prevent temporary copy operations. std::in_place is used for this purpose:

    • std::make_optional method can also be used for instantiation of std::optional objects like in smart pointers. In this case, std::in_place is not required:

    • std::optional can also be used with STL containers:

  • How can we access the contained values?
    • value() API can be used to access the value contained in std::optional instance. If given instance does not contain any value, then std::bad_optional_access exception is thrown,
    • In addition to value() API, pointer operators such as * and -> can also be used with std::optional instances. Contrary to previous usage, if instance does not contain any value, then no exception is thrown and behavior is undefined. So you have to be careful 🙂

    • Lastly, value_or(defaultValue) API is also provided with optional library which returns defaultValue if given std::optional instance does not contain any value.

  • How can we check if given std::optional instance contain any value?
    • has_value() API can be used to query if given instance contain any value,
    • operator bool() is also defined and can be used with conditional statements such as if-else if,
    • Example usages are provided below:

  • How can we update existing value?
    • Assignment operator (=) ve emplace() API can be used for this purpose:

    • * operator can also be used for assignment, but the given std::optional instance should contain a value:

    • std::optional<> also support move semantics. In other words, std::move can be used to transfer instances from other instances.
  • Can we use comparison operators?
    • You can use standard comparison operators with std::optional instances.

    • If both of instances do no contain any value, == comparison returns true. If one instance does not contain any value, then different results can be observed such that no value instance always considered less than other instance that contain value. Let us look at example usages:

  • How std::optional can be used for function returns is given in the sample code that is provided at the beginning of my post.
  • reset() API can be used to reset/clear the value contained in given instance.

It is time to look at two complete code examples which illustrate basic std::optional usages. I took first example from the book that I gave in references section:

The other example code is taken from CPP reference page. I hope these two example codes help you to understand std::optional better. 

See you in my next post. Have plenty of coding 🙂

References:

https://www.boost.org/doc/libs/1_70_0/libs/optional/doc/html/boost_optional/tutorial/when_to_use_optional.html

https://en.cppreference.com/w/cpp/utility/optional

https://arne-mertz.de/2018/06/modern-c-features-stdoptional/

C++ 17 The Complete Guide, Nicolai M. Josuttis

https://www.fluentcpp.com/2016/11/24/clearer-interfaces-with-optionalt/

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.