假设我有一个班级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 次 |
| 最近记录: |