为什么std :: optional :: value()&&amp ;;回归&&amp ;?

时间:2017-09-14 12:34:01

标签: c++ c++17 stdoptional

我使用std :: optional:

替换了一些代码时遇到了运行时错误

旧代码:

T getValue();
...
const auto& value = getValue();
value.get();

新代码:

std::optional<T> getValue();
...
const auto& value = getValue().value();
value.get(); // Runtime error, crash 

这对我来说无法预测。 崩溃的原因是该方法返回T&&

我的问题是T&&在哪些情况下有用,为什么该方法不返回T

完整代码:

#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;
}

2 个答案:

答案 0 :(得分:5)

这是两个相互竞争的需求造成的一个小设计缺陷。

首先,避免额外的移动,第二次启用参考生命周期扩展。

这两个在当前的C ++中竞争;你通常不能同时解决这两个问题。所以你会看到代码在做一个或另一个,非常随意。

我个人发现返回一个右值引用来产生更多问题,而不是从即将被销毁的对象移动,但标准化std::optional的人不同意。

我的首选解决方案还有其他缺点。

要解决这个问题 - 不必做出这些妥协 - 我们需要对生命周期扩展的工作原理进行复杂的重新定义。所以我们现在必须忍受这些问题。

答案 1 :(得分:1)

返回std::optional<std::array<T, N>> getOptional(); 部队移动构造它,而返回(rvalue-)引用没有成本。

假设你有

getOptional().value()

然后

{{1}}

会做几个副本(RVO不会在这里申请,因为它会返回(移动)成员。)