Hacker News new | ask | show | jobs
by jzwinck 1064 days ago
std::optional is not a pointer. And it has a safe dereference method called value() if you want the extra runtime check which operator* skips.
2 comments

C++ got this wrong, again. The default usage should be safe, with an escape hatch, i.e. deref operator should be safe and value() should be unsafe.

Ideally, a sufficiently smart compiler would be able to see code like

    if (auto t = get_optional())
    {
        do_something(*t);
    }
And elide the double safety check, but because optional is a library feature not a language feature, the compiler needs to detect general usages of that pattern rather than specifically optimising for a language level construct. That's another place c++ is going in the wrong direction in...
The default option is high performance and less verbose.
The default option is dangerous and vulnerable being incorrect unless you explicitly use it in a different way. This is a symptom of it being a library and not a language feature.

As another example, imagine if span was a language feature. A compiler could bounds check at compile time, and fully elide the checks at runtime in many scenarios (like in a loop over the span).

A pointer with an opt-in, less convenient, safe dereference... is still a pointer. You could add a `value` observer to unique_ptr or shared_ptr.

The entire point of optional is that you can swap it in for a raw or unique pointer and it'll be cheaper because no allocation. That's not the use case for an option type.

It's not a pointer. `std::optional<T>` is a class that directly contains a `T` (within a union) and happens to offer `operator*` and `operator->` providing an API similar to a smart pointer. This does not make it a pointer (there's nothing else it could be pointing to).

Also, in an ideal world, stdlib implementations would support error-checking for `std::optional::operator*`. "Undefined behavior" just means the standard doesn't specify what should happen. Both "let's use it for unsafe optimizations" and "trigger assertion failures" are valid implementions of undefined behavior, and a good implemention should allow the user to make this choice. For gcc, see -D_GLIBCXX_ASSERTIONS. Though I'll say that it's unfortunate that C++ implementations tend to default to "unsafe optimizations" and that the opt-in to safety is not standardized.