为什么 std::optional::value() &&; return &&?
Why std::optional::value() &&; return &&?
当使用 std::optional:
替换一些代码时,我遇到了运行时错误
旧代码:
T getValue();
...
const auto& value = getValue();
value.get();
新代码:
std::optional<T> getValue();
...
const auto& value = getValue().value();
value.get(); // Runtime error, crash
这对我来说是不可预测的。
崩溃的原因是方法returns T&&
.
我的问题是T&&
在什么情况下会有用,为什么方法return没有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;
}
返回 T
强制移动构造它,而 returning (rvalue-)reference 没有成本。
假设你有
std::optional<std::array<T, N>> getOptional();
然后
getOptional().value()
会复制几份(RVO 在这里不适用,因为它会 return 一个(移动的)成员)。
这是两个相互竞争的需求造成的一个小设计缺陷。
首先,避免额外的移动,其次实现参考寿命延长。
这两个在当前的 C++ 中竞争;您通常无法同时解决这两个问题。所以你会看到代码非常随意地做一个或另一个。
我个人认为返回一个右值引用比从一个即将被销毁的对象移动产生更多的问题,但标准化的人 std::optional
不同意。
我的首选解决方案还有其他缺点。
为了解决这个问题——不必做出这些妥协——我们需要对生命周期延长的工作原理进行复杂而混乱的重新定义。所以我们现在不得不忍受这些问题。
当使用 std::optional:
替换一些代码时,我遇到了运行时错误旧代码:
T getValue();
...
const auto& value = getValue();
value.get();
新代码:
std::optional<T> getValue();
...
const auto& value = getValue().value();
value.get(); // Runtime error, crash
这对我来说是不可预测的。
崩溃的原因是方法returns T&&
.
我的问题是T&&
在什么情况下会有用,为什么方法return没有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;
}
返回 T
强制移动构造它,而 returning (rvalue-)reference 没有成本。
假设你有
std::optional<std::array<T, N>> getOptional();
然后
getOptional().value()
会复制几份(RVO 在这里不适用,因为它会 return 一个(移动的)成员)。
这是两个相互竞争的需求造成的一个小设计缺陷。
首先,避免额外的移动,其次实现参考寿命延长。
这两个在当前的 C++ 中竞争;您通常无法同时解决这两个问题。所以你会看到代码非常随意地做一个或另一个。
我个人认为返回一个右值引用比从一个即将被销毁的对象移动产生更多的问题,但标准化的人 std::optional
不同意。
我的首选解决方案还有其他缺点。
为了解决这个问题——不必做出这些妥协——我们需要对生命周期延长的工作原理进行复杂而混乱的重新定义。所以我们现在不得不忍受这些问题。