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?
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
The class template std::optional manages an optional contained value, i.e. a value that may or may not be present. A common use case for optional is the return value of a function that may fail.
std::optional<T> provides safeties for all these things: Its instances can be created at stack level, so there will not be extra allocation, deallocation or null-references: RAII will take care of them (though this depends on the actual Standard Library implementation).
std::move itself does "nothing" - it has zero side effects. It just signals to the compiler that the programmer doesn't care what happens to that object any more. i.e. it gives permission to other parts of the software to move from the object, but it doesn't require that it be moved.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With