避免返回参考引用参数 [英] Avoid returning by-reference argument

查看:120
本文介绍了避免返回参考引用参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个类 Option

  template< typename T> 
class Option {
public:
Option()noexcept
{}

选项(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 是当此选项为空时返回的默认值:

  ; int> X; // empty 
int y = 123;
x.getOrElse(y); // == 123

但是,我认为以下代码不安全:

 选项< int> X; 
x.getOrElse(123); //引用临时变量!

一种更安全的方法是通过 Option :: getOrElse ,但是当 Option 不为空时,这将是浪费。

更新:我想的是可能重载的参数类型(lvalue / rvalue)<$



更新2:也许这个?

  T getOrElse(T& x)const {...} 

const T& getOrElse(const T& x)const {...}

但我认为这可能是模糊的因为左值和右值参数都适合第二个版本。

解决方案


不安全:

 选项< int> X; 
x.getOrElse(123); //引用临时变量!


这是为什么 std :: optional :: value_or()返回 T 而不是 T& T const& 。根据 N3672


有人认为函数应该返回常量引用而不是值,这样可以避免某些情况下的复制开销:

  void observe(const X& x); 

可选< X> ox {/ * ... * /};
observe(ox.value_or(X {args})); //不必要的副本

但是,函数value_or的好处仅在提供可选对象时可见作为临时(没有名称);否则,三元运算符同样有用:

 可选< X> ox {/ * ... * /}; 
observe(ox?* ok:X {args}); // no copy

此外,通过引用返回将很可能渲染悬挂引用,可选对象被释放,因为第二个参数通常是临时的:

 可选< X> ox {nullopt}; 
auto&&& x = ox.value_or(X {args});
cout<< X; // x is dangling!


我建议您遵循相同的指南。如果你真的需要避免复制,使用三元。这是安全无恙的:

 可选< int> ox = ...; 
const int& val = ox? * ox:123;

如果你真的没有,或 Optional 是一个右值, getOrElse()更简洁。


Suppose I have a class 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_;
};

The argument passed to Option::getOrElse is the default value to return when this Option is empty:

Option<int> x;  // empty
int y = 123;
x.getOrElse(y);  // == 123

However, I think the following code is not safe:

Option<int> x;
x.getOrElse(123);  // reference to temporary variable!

A safer way would be to return by value from Option::getOrElse, but that would be wasteful when the Option is non-empty. Can I work around this somehow?

UPDATE: I'm thinking about perhaps overloading on the argument type (lvalue/rvalue) of getOrElse, but haven't figured out exactly how to do so.

UPDATE 2: Maybe this?

T getOrElse(T &&x) const { ... }

const T & getOrElse(const T &x) const { ... }

But I think this might be ambiguous because both lvalue and rvalue arguments fit the second version.

解决方案

However, I think the following code is not safe:

Option<int> x;
x.getOrElse(123);  // reference to temporary variable!

You are correct. This is why std::optional::value_or() returns a T and not a T& or T const&. As per the rationale in 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!

I suggest you follow the same guidelines. If you really need to avoid the copy, use a ternary. This is safe and copyless:

Optional<int> ox = ...;
const int& val = ox ? *ox : 123;

If you really don't, or the Optional is an rvalue anyway, getOrElse() is more concise.

这篇关于避免返回参考引用参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆