I have had runtime error, when replaced some code by using std::optional:
Old code:
T getValue();
...
const auto& value = getValue();
value.get();
New code:
std::optional<T> getValue();
...
const auto& value = getValue().value();
value.get(); // Runtime error, crash
It was unpredictable for me.
The reason of crash is that the method returns T&&
.
My question is in what cases T&&
can be useful, why the method does not return a T
.
Complete code:
#include <experimental/optional>
#include <iostream>
#include <memory>
struct Value {
std::unique_ptr<int> a = std::make_unique<int>(5);
};
std::experimental::optional<Value> getValue() {
Value v;
return v;
}
int main() {
const Value& value = getValue().value();
std::cout << *value.a << std::endl;
return 0;
}
std::optional contains the object within itself, depending on where it is stored (stack/data/heap) std::optional makes a copy of the contained object. Monadic functions will be added in C++23 to improve the abstraction in our code by removing the needs of writing boilerplate code.
(since C++17) 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.
Optional is immutable, so it's automatically thread safe.
What's more, std::optional doesn't need to allocate any memory on the free store. std::optional is a part of C++ vocabulary types along with std::any , std::variant and std::string_view .
It is a minor design flaw caused by two competing needs.
First, avoiding extra moves, and second enabling reference lifetime extension.
These two compete in current C++; you usually cannot solve both problems at once. So you will see code doing one or the other, quite haphazardly.
I personally find returning an rvalue reference to generate more problems than moving from a soon to be destroyed object, but those who standardized std::optional
disagreed.
My preferred solution would have other downsides.
To fix this—to not have to make these compromises—we would require a complex messy redefinition of how lifetime extension works. So we have to live with these problems for now.
Returning T
forces to move construct it, whereas returning (rvalue-)reference has no cost.
Let suppose that you have
std::optional<std::array<T, N>> getOptional();
then
getOptional().value()
would do several copies (RVO doesn't apply here as it would return a (moved) member).
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