5

当使用 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;
}
4

2 回答 2

7

这是由两个相互竞争的需求引起的一个小设计缺陷。

首先,避免额外的移动,其次是启用参考寿命延长。

这两个在当前的 C++ 中竞争;你通常不能同时解决这两个问题。因此,您会看到代码非常随意地执行其中一个或另一个。

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

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

为了解决这个问题——不必做出这些妥协——我们需要对延长寿命的工作方式进行复杂而混乱的重新定义。所以我们现在必须忍受这些问题。

于 2017-09-14T12:51:25.737 回答
1

返回T强制移动构造它,而返回(右值)引用没有成本。

假设你有

std::optional<std::array<T, N>> getOptional();

然后

getOptional().value()

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

于 2017-09-14T12:49:22.200 回答