假设我有一个班级Option
:
template<typename T>
class Option {
public:
Option() noexcept
{}
Option(T val) noexcept : val_(std::make_shared<T>(std::move(val)))
{}
const T & get() const
{
if (val_ == nullptr) {
throw std::out_of_range("get on empty Option");
}
return *val_;
}
const T & getOrElse(const T &x) const
{
return val_ == nullptr ? x : *val_;
}
private:
std::shared_ptr<T> val_;
};
Run Code Online (Sandbox Code Playgroud)
传递给的参数Option::getOrElse
是当它Option
为空时返回的默认值:
Option<int> x; // empty
int y = 123;
x.getOrElse(y); // == 123
Run Code Online (Sandbox Code Playgroud)
但是,我认为以下代码不安全:
Option<int> x;
x.getOrElse(123); // reference to temporary variable!
Run Code Online (Sandbox Code Playgroud)
更安全的方式是从值返回Option::getOrElse
,但是当Option
非空时,这将是浪费.我可以以某种方式解决这个问题吗?
更新:我正在考虑可能在参数类型(lvalue/rvalue)上重载getOrElse
,但还没有弄清楚到底是怎么做的.
更新2:也许这个?
T getOrElse(T &&x) const { ... }
const T & getOrElse(const T &x) const { ... }
Run Code Online (Sandbox Code Playgroud)
但我认为这可能是模棱两可的,因为左值和右值都适合第二个版本.
但是,我认为以下代码不安全:
Run Code Online (Sandbox Code Playgroud)Option<int> x; x.getOrElse(123); // reference to temporary variable!
你是对的。这就是为什么std::optional::value_or()
返回 aT
而不是 a T&
or的原因T const&
。根据N3672中的基本原理:
有人认为函数应该通过常量引用而不是值返回,这可以避免某些情况下的复制开销:
Run Code Online (Sandbox Code Playgroud)void observe(const X& x); optional<X> ox { /* ... */ }; observe( ox.value_or(X{args}) ); // unnecessary copy
然而,只有当可选对象作为临时对象(没有名称)提供时,函数 value_or 的好处才可见;否则,三元运算符同样有用:
Run Code Online (Sandbox Code Playgroud)optional<X> ox { /* ... */ }; observe(ox ? *ok : X{args}); // no copy
此外,如果可选对象被解除,通过引用返回可能会呈现悬空引用,因为第二个参数通常是临时的:
Run Code Online (Sandbox Code Playgroud)optional<X> ox {nullopt}; auto&& x = ox.value_or(X{args}); cout << x; // x is dangling!
我建议您遵循相同的准则。如果您确实需要避免复制,请使用三元。这是安全且无复制的:
Optional<int> ox = ...;
const int& val = ox ? *ox : 123;
Run Code Online (Sandbox Code Playgroud)
如果你真的不这样做,或者Optional
无论如何它是一个右值,getOrElse()
那就更简洁了。
归档时间: |
|
查看次数: |
372 次 |
最近记录: |