假设我有一个类 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_;
};
传递给 Option::getOrElse
的参数是当此 Option
为空时返回的默认值:
Option<int> x; // empty
int y = 123;
x.getOrElse(y); // == 123
但是,我认为下面的代码是不安全的:
Option<int> x;
x.getOrElse(123); // reference to temporary variable!
一种更安全的方法是从 Option::getOrElse
中按值返回,但是当 Option
为非空时,这会很浪费。我能以某种方式解决这个问题吗?
更新:我正在考虑是否重载 getOrElse
的参数类型(左值/右值),但还没有弄清楚具体如何操作。
更新 2:可能是这个?
T getOrElse(T &&x) const { ... }
const T & getOrElse(const T &x) const { ... }
但我认为这可能有歧义,因为左值和右值参数都符合第二个版本。
最佳答案
However, I think the following code is not safe:
Option<int> x; x.getOrElse(123); // reference to temporary variable!
你是对的。这就是为什么 std::optional::value_or()
返回 T
而不是 T&
或 T const&
.根据 N3672 中的理由:
It has been argued that the function should return by constant reference rather than value, which would avoid copy overhead in certain situations:
void observe(const X& x); optional<X> ox { /* ... */ }; observe( ox.value_or(X{args}) ); // unnecessary copy
However, the benefit of the function value_or is only visible when the optional object is provided as a temporary (without the name); otherwise, a ternary operator is equally useful:
optional<X> ox { /* ... */ }; observe(ox ? *ok : X{args}); // no copy
Also, returning by reference would be likely to render a dangling reference, in case the optional object is disengaged, because the second argument is typically a temporary:
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;
如果你真的不这样做,或者 Optional
无论如何都是一个右值,getOrElse()
会更简洁。
关于c++ - 避免返回引用参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36993646/