有没有返回RValue Reference(&&)有用的情况?

时间:2011-04-24 11:30:34

标签: c++ c++11 move-semantics rvalue-reference

函数是否应该返回RValue Reference ?技巧,技巧,成语或模式?

MyClass&& func( ... );

我一般都知道returning references的危险,但有时候我们会这样做,不管怎样我们(T& T::operator=(T)只是一个惯用的例子)。但T&& func(...)怎么样?我们会从中获得这样的一般场所吗?与仅使用客户端代码相比,编写库或API代码时可能会有所不同吗?

5 个答案:

答案 0 :(得分:56)

在某些情况下它是合适的,但它们相对罕见。当您希望允许客户端从数据成员移动时,在一个示例中出现这种情况。例如:

template <class Iter>
class move_iterator
{
private:
    Iter i_;
public:
    ...
    value_type&& operator*() const {return std::move(*i_);}
    ...
};

答案 1 :(得分:17)

这是对towi评论的跟进。您永远不想返回对局部变量的引用。但你可能有这个:

vector<N> operator+(const vector<N>& x1, const vector<N>& x2) { vector<N> x3 = x1; x3 += x2; return x3; }
vector<N>&& operator+(const vector<N>& x1, vector<N>&& x2)    { x2 += x1; return std::move(x2); }
vector<N>&& operator+(vector<N>&& x1, const vector<N>& x2)    { x1 += x2; return std::move(x1); }
vector<N>&& operator+(vector<N>&& x1, vector<N>&& x2)         { x1 += x2; return std::move(x1); }

这应该可以防止所有情况下的任何副本(和可能的分配),除非两个参数都是左值。

答案 2 :(得分:7)

没有。只需返回值。返回引用通常并不危险 - 它返回对 local 变量的引用是危险的。然而,返回一个右值引用在几乎所有情况下都是毫无价值的(我想如果你正在编写std::move或其他东西)。

答案 3 :(得分:0)

如果您确定在函数退出后引用的对象不会超出范围,则可以通过引用返回,例如它是一个全局对象的引用,或者返回对类字段等的引用的成员函数。

此返回参考规则与左值和右值参考相同。不同之处在于您希望如何使用返回的引用。正如我所看到的,通过右值参考返回很少见。如果你有功能:

Type&& func();

你不会喜欢这样的代码:

Type&& ref_a = func();

因为它有效地将ref_a定义为Type&amp;由于命名的右值参考是左值,因此这里不会执行实际的移动。这很像:

const Type& ref_a = func();

除了实际的ref_a是非const左值引用。

即使你直接将func()传递给另一个带有Type&amp;&amp;&amp;的函数,它也不是很有用。参数,因为它仍然是该函数内的命名引用。

void anotherFunc(Type&& t) {
  // t is a named reference
}
anotherFunc(func());

func()和anotherFunc()的关系更像是一个“授权”,func()同意anotherFunc()可能会从func()获取返回对象的所有权(或者你可以说“窃取”)。但这个协议非常宽松。一个非常量左值参考仍然可以被呼叫者“窃取”。实际上很少定义函数来获取rvalue引用参数。最常见的情况是“anotherFunc”是一个类名,而anotherFunc()实际上是一个移动构造函数。

答案 4 :(得分:0)

另一种可能的情况:当您需要解压缩元组并将值传递给函数时。

如果您不确定copy-elision,那么在这种情况下它可能很有用。

这样的例子:

template<typename ... Args>
class store_args{
    public:
        std::tuple<Args...> args;

        template<typename Functor, size_t ... Indices>
        decltype(auto) apply_helper(Functor &&f, std::integer_sequence<size_t, Indices...>&&){
            return std::move(f(std::forward<Args>(std::get<Indices>(args))...));
        }

        template<typename Functor>
        auto apply(Functor &&f){
            return apply_helper(std::move(f), std::make_index_sequence<sizeof...(Args)>{});
        }
};

非常罕见的情况,除非您正在编写某种形式的std::bindstd::thread替代品。