Lesson 123 +10 XP

std::optional

std::optional

Some results simply don't exist: a search finds nothing, a function fails. std::optional wraps that idea - a value or nothing.

The object holds a value or nothing

#include <optional>
using namespace std;

optional<int> maybe;        // empty, holds no value
optional<int> num = 42;    // holds the value 42

optional<int> is like a box that either contains an int or contains nothing at all.

Ask with has_value

if (num.has_value()) {
    cout << "The box has a value" << endl;
}

.has_value() returns true exactly when the optional is holding a value.

Get the value out

cout << *num << endl;        // 42  (dereference, like a pointer)
cout << num.value() << endl; // 42  (checked version)
  • num - the dereference. On an empty* optional this is undefined behavior.
  • .value() - the checked version. On an empty optional it throws an exception.

Optional as a return type

optional<int> findGrade(bool tookExam) {
    if (!tookExam) return nullopt;  // no value
    return 88;                      // a real value
}

auto g = findGrade(false);
if (g.has_value()) {
    cout << g.value();
}

nullopt is the constant that means "no value". Returning it signals a missing result honestly - no magic -1 needed.

Press a fallback: value_or

int score = maybe.value_or(0);   // the value, or 0 if empty

.value_or(default) returns the value if present, otherwise the default.

TL;DR

  • std::optional<T> stores a value, or nothing.
  • Check with .has_value().
  • Read with * (unchecked) or .value() (throws if empty).
  • nullopt is the value for "no result".
  • .value_or(default) gives a fallback.