【问题标题】:Why std::optional::value() &&; return &&?为什么 std::optional::value() &&;返回 &&?
【发布时间】:2018-02-23 10:48:29
【问题描述】:

当使用 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&amp;&amp;

我的问题是T&amp;&amp; 在什么情况下有用,为什么该方法不返回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;
}

【问题讨论】:

  • 另外,如果您要返回参考,this 可能是相关的。
  • 如果它返回/*const*/T&amp; BTW,你会遇到类似的问题。
  • 返回T 会多出一个move
  • 在您的旧代码中,您将临时 T 分配给 T&。我永远不会那样做。即使它以某种方式起作用,它也会令人困惑并且没有意义,并且只是在乞求问题。这对你来说不是一个悬而未决的参考吗?即使标准的某些晦涩的方面允许它工作,它也没有任何意义。如果要保留该值,请将其分配给一个值,而不是引用。我会说 C++ 中的设计缺陷(如果有的话)是您的旧代码完全可以工作。

标签: c++ c++17 stdoptional


【解决方案1】:

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

首先,避免额外的移动,其次是启用引用生命周期延长。

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

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

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

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

【讨论】:

    【解决方案2】:

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

    假设你有

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

    然后

    getOptional().value()
    

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

    【讨论】:

      猜你喜欢
      • 2017-10-31
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      相关资源
      最近更新 更多