Skip to content

Intermediate Gotchas

The Default That Was Loaded Anyway

the optional with a value that still calls the fallback

std::string default_name() {
  std::cout << "loading default\n";
  return "Guest";
}

int main() {
  std::optional<std::string> name = "Ada";
  const std::string chosen = name.value_or(default_name());

  std::cout << "name: " << chosen << '\n';
}

Does default_name run when name already contains "Ada"?

Answer
loading default
name: Ada

The fallback was loaded, then thrown away.

Why

value_or is an ordinary function call. C++ evaluates its argument, default_name(), before entering that function, whether or not the optional already holds a value. The function then returns the contained "Ada", so the eager fallback result is unused. A conditional expression evaluates only its selected arm and is lazy in the way value_or is not.

The fix

const std::string chosen = name ? *name : default_name();

Takeaway: value_or(expr) receives an already-evaluated value; use a conditional when producing the fallback is expensive or has effects.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry