Take value out of std::optional
Asked Answered
S

2

16

How do you actually take a value out of optional? Meaning take ownership of the value inside the std::optional and replace it with std::nullopt (or swap it with another value)?

In Rust for example you could .unwrap your Option or do something like foo.take().unwrap(). I'm trying to do something like that with C++ optionals.

Sonorant answered 23/4, 2022 at 13:20 Comment(0)
E
12

operator*/value() returns a reference to the value held by the optional, so you can simply use std::move to move it to a temporary variable

std::optional<std::string> opt = "abc";
// "take" the contained value by calling operator* on a rvalue to optional
auto taken = *std::move(opt);

This will invoke the rvalue reference overload of operator*() of the optional, which returns an rvalue reference to the contained value.

You can also directly perform std::move on the return value of the operator*() of the lvalue optional, which will convert the lvalue reference of the contained value into an rvalue

auto taken = std::move(*opt);
Eaton answered 23/4, 2022 at 13:26 Comment(1)
opt still contains (moved-from) value after that. Ideally you should follow-up with .reset(). Also, tangential, but *std::move(opt) and std::move(*opt) are equivalent.Flinders
P
4

The standard way in C++ to replace a value and return the old, like mem::replace in Rust, is std::exchange.

So:

std::exchange(o, std::nullopt).value();

https://godbolt.org/z/G7faK9rxj

Phototaxis answered 23/4, 2022 at 15:35 Comment(2)
Thanks! Can you please explain why this works? I'm super new to C++ and two things that I don't understand - 1) why does exchange work here and 2) why does .value() not return a reference instead?Sonorant
std::exchange copies the value of the first argument (o), then assigns the second argument to the first (o = std::nullopt) and then returns the copy, i.e. the old value of the first argument (what was in o before). It returns by value. Because std::exchange(o, std::nullopt) is a temporary, when you call .value() on it, you get an rvalue reference, and so assignment will move from it.Phototaxis

© 2022 - 2024 — McMap. All rights reserved.