Skip to content
C++ Basics: Avoid Unnecessary Work in Optional Fallbacks

C++ Basics: Avoid Unnecessary Work in Optional Fallbacks

November 7, 2026

A fallback passed to value_or is evaluated even when an optional already contains a value. Use a conditional when producing that fallback is expensive.

Prepare a scratch directory

Tested on Linux x86_64 with GCC 14.2.0. Install a C++20-capable compiler and standard-library development headers, with g++ on PATH. You also need Bash, a text editor, and the mktemp, rm, and rmdir utilities. No third-party library is required.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as optional-eager-fallback-demo.cpp:

#include <iostream>
#include <optional>

int fallback(int& calls)
{
    ++calls;
    return 90;
}

int main()
{
    const std::optional<int> configured{12};
    int calls = 0;
    const int eager = configured.value_or(fallback(calls));
    std::cout << "eager: " << eager << ", calls=" << calls << '\n';
    calls = 0;
    const int lazy = configured ? *configured : fallback(calls);
    std::cout << "lazy: " << lazy << ", calls=" << calls << '\n';
    const std::optional<int> missing;
    const int defaulted = missing ? *missing : fallback(calls);
    std::cout << "missing: " << defaulted << ", calls=" << calls << '\n';
}

Compile and run it. The program runs only after compilation succeeds:

g++ -std=c++20 -Wall -Wextra -Werror -pedantic optional-eager-fallback-demo.cpp -o optional-eager-fallback-demo &&
./optional-eager-fallback-demo

Observed output:

eager: 12, calls=1
lazy: 12, calls=0
missing: 90, calls=1

Read the result

Both configured results are 12, but only the value_or call invokes the fallback. The conditional evaluates just its selected operand. A missing value still invokes the fallback once.

Apply it carefully

value_or is a normal function call: its argument is computed before the function selects a result. It returns a value, not a reference into the optional. Use it freely for cheap constants; use explicit branching for expensive or side-effecting work. Check engagement before dereferencing.

The C++ working draft describes the relevant rules. This example builds in C++20 mode; the current working draft also documents later additions.

Clean up

Remove only the source and executable created here, then return to the starting directory:

rm -- optional-eager-fallback-demo.cpp optional-eager-fallback-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on