29

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?

4

2 回答 2

26

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.

于 2013-07-06T12:39:25.003 回答
-1

For your current implementation the answer is NO. But if you slightly change it you'll be able to move the value. There are 4 overloads for optional's operator * (as well as for method value()). And there are just 2 of them returning rvalue reference (_Ty && and const _Ty &&) to encapsulated value. But they have signature && and const && respectively. It means you can use them only if your optional variable itself is accessed by rvalue reference. In this case the implementation should look like:

std::optional<Content> Parse(const std::string& data);
void Process(Content content);

int main()
{
    auto data = ReadData();
    auto content = Parse(data);
    if (content)
        Process(*std::move(content));
}
于 2019-08-09T14:08:51.050 回答