Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to move from std::optional<T>

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?

like image 481
hansmaad Avatar asked Jul 06 '13 11:07

hansmaad


People also ask

What does std :: move () do?

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.

What is std :: optional for?

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.

Is std :: optional on stack?

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).

Do I need std :: move?

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.


1 Answers

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.

like image 61
mavam Avatar answered Oct 07 '22 14:10

mavam