5

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; } 
5
  • 5
    Please edit your question with an minimal reproducible example or SSCCE (Short, Self Contained, Correct Example) Commented Sep 14, 2017 at 12:34
  • Also, this is probably relevant if you are returning a reference. Commented Sep 14, 2017 at 12:37
  • You would have similar issue if it returns /*const*/T& BTW. Commented Sep 14, 2017 at 12:39
  • Returning a T would do one extra move. Commented Sep 14, 2017 at 12:41
  • In your old code, you assign a temporary T to a T&. I would never do that. Even if it somehow works, it's confusing and doesn't make sense and is just begging for problems. Wouldn't that seem like a dangling reference to you? Even if there's some obscure aspect of the standard which allows it to work, it doesn't make sense. If you want to keep the value around, assign it to a value, not to a reference. I would say the design flaw, if any, in C++ is that your old code works at all. Commented Dec 25, 2019 at 15:11

2 Answers 2

7

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.