It’s the abort that is the crux of the issue here. Usually you would pass the std::optional up/down the call stack. If you don’t control the types (e.g. using a library or a framework) you’d come up with some “default” value instead, like this:
But sometimes there’s no good “default” value, and then you have to resort to just unwrap-ing the value, and accepting that the entire program will abort when that function call fails. Usually this is a sign of poor engineering somewhere, likely in a library you’re using, and should be fixed; but sometimes you don’t have the time to fix it, and then it ends up in production.
It’s worse than just exceptions in C++. There’s (almost) no way for the caller of your function to catch it. It’s a bit like this snippet:
std::optional<int> foo = <...>; try { return foo.value(); } catch(const std::bad_optional_access& e) { std::cout << e.what() << std::endl; abort(); }It’s the
abortthat is the crux of the issue here. Usually you would pass thestd::optionalup/down the call stack. If you don’t control the types (e.g. using a library or a framework) you’d come up with some “default” value instead, like this:std::optional<int> foo = <...>; return foo.value_or(123);Or in Rust:
let foo : Option<i32> = <...>; return foo.unwrap_or(123);But sometimes there’s no good “default” value, and then you have to resort to just
unwrap-ing the value, and accepting that the entire program will abort when that function call fails. Usually this is a sign of poor engineering somewhere, likely in a library you’re using, and should be fixed; but sometimes you don’t have the time to fix it, and then it ends up in production.