81

函数应该返回 RValue 引用是否有原因?一种技术、技巧、习语或模式?

MyClass&& func( ... );

我知道一般返回引用的危险,但有时我们还是会这样做,不是吗?T& T::operator=(T)只是一个惯用的例子。但是怎么样T&& func(...)?是否有任何一般的地方可以让我们从中受益?与仅编写客户端代码相比,编写库或 API 代码时可能有所不同?

4

5 回答 5

61

合适的场合有少数,但比较少见。当您希望允许客户端从数据成员移动时,这种情况出现在一个示例中。例如:

template <class Iter>
class move_iterator
{
private:
    Iter i_;
public:
    ...
    value_type&& operator*() const {return std::move(*i_);}
    ...
};
于 2011-04-24T13:54:59.643 回答
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); }

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

于 2011-05-02T04:27:15.677 回答
8

不,只需返回值。一般来说,返回引用一点也不危险——它返回对局部变量的引用,这是危险的。然而,返回一个右值引用在几乎所有情况下都是毫无价值的(我猜如果你在写std::move什么的)。

于 2011-04-24T11:34:34.603 回答
1

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

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

Type&& func();

你不会喜欢这样的代码:

Type&& ref_a = func();

因为它有效地将 ref_a 定义为 Type& 因为命名的右值引用是一个左值,所以这里不会执行实际的移动。这很像:

const Type& ref_a = func();

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

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

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

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

于 2015-07-27T23:49:18.557 回答
0

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

如果您不确定复制省略,这在这种情况下可能很有用。

这样的例子:

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::bind罕见std::thread

于 2015-07-28T00:03:06.173 回答