Consider the following example where we parse data and pass the result to the next function:
Content Parse(const std::string& data);
void Process(Content content);
int main()
{
auto data = ReadData();
Process(Parse(data));
}
Now let's change the code using std::optional
to handle a failed parsing step:
optional<Content> Parse(const std::string& data);
void Process(Content content);
int main()
{
auto data = ReadData();
auto content = Parse(data);
if (content)
Process(move(*content));
}
Is it valid to move from optional<T>::value()
? If it's ok for std::optional
is it valid for boost::optional
as well?
It is valid to move from optional<T>::value()
since it returns a mutable reference and the move does not destroy the object. If the optional
instance is not engaged, value()
will throw a bad_optional_access
exception (§20.6.4.5).
You explicitly check whether the option is engaged:
if (content)
Process(move(*content));
But you don't use the member value()
to access the underlying T
. Note that value()
performs a check internally before returning a valid T&
, unlike operator*
which has a precondition that the optional
instance shall be engaged. This is a subtle difference, but you use the right idiom:
if (o)
f(*o)
as opposed to
if (o) // redundant check
f(o.value())
In Boost, the situation is a little different: first, there exists no member function called value()
that provides checked access. (A bad_optional_access
exception simply does not exist). The member get()
is just an alias for operator*
and always relies on the user checking that the optional
instance is engaged.