函数应返回RValue引用吗?一种技术,技巧,成语或模式?
MyClass&& func( ... );
我知道一般会返回引用的危险,但是有时候我们还是这样做,不是吗?T& T::operator=(T)
只是一个惯用的例子。但是T&& func(...)
呢?有没有一般的地方可以从中受益呢?与仅编写客户端代码相比,编写库或API代码时可能有所不同吗?
Answers:
在少数情况下,这是适当的,但它们相对较少。在一个示例中,当您要允许客户端从数据成员转移时,就会出现这种情况。例如:
template <class Iter>
class move_iterator
{
private:
Iter i_;
public:
...
value_type&& operator*() const {return std::move(*i_);}
...
};
value_type
代替value_type&&
返回类型使用会更安全吗?
const X& x = *i
情况很少见。我认为我从未见过。
这是关于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); }
这应该在所有情况下都防止任何副本(以及可能的分配),除非两个参数均为左值。
return std::move(x2);
。或者您可以编写强制转换为rvalue引用类型的强制转换,但是move
无论如何,这就是工作。
否。只需返回值即可。通常,返回引用完全没有危险-它返回对局部变量很危险的引用。但是,在几乎所有情况下(如果您正在写std::move
东西),返回右值引用都是毫无价值的。
T&& operator+(const T&,T&&)
应返回&&
。但是,最终草案现在已不复存在。这就是为什么我问。
如果您确定所引用的对象在函数退出后不会超出范围,则可以按引用返回,例如,它是全局对象的引用,或者成员函数返回对类字段的引用等。
返回的参考规则与左值和右值参考相同。区别在于您要如何使用返回的引用。如我所见,通过右值引用返回的情况很少见。如果您具有功能:
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()实际上是一个移动构造函数。
还有一种可能的情况:当您需要解压缩元组并将值传递给函数时。
如果您不确定复制删除,在这种情况下可能会很有用。
这样的例子:
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
替换,否则这种情况很少见。