一句话,直接返回即可,一般不用任何特殊写法。
当启动了c++11选项后,通过函数返回代码没有发生任何变化,但是已经使用了move语义,而不一定使用之前介绍的NRVO编译器优化技术。
注意,右值引用rvalue reference是表达式计算完成后就不再存在的临时变量,左值是表达式计算完成后的变量。如果能够用&求址的,就是左值。
下面是stackoverflow上的一个讨论贴,比较有价值:
结论是:
1. 应该按照正常写法(Best Practice)返回local 变量
2. 编译器会决定要么使用NRVO,要么使用Move语义来优化返回语句
如果使用条件语句返回,会抑制编译器使用NRVO
也不要将返回的值包装在另一个函数中返回,而应该仅仅返回local变量
如果要返回一个local变量内的成员变量,需要显式的使用move
3. 如果使用Move语义,需要返回的类型有move constructor,否则只会进行复制
First example1
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> &&rval_ref = return_vector();
The first example returns a temporary which is caught by rval_ref
. That temporary will have its life extended beyond the rval_ref
definition and you can use it as if you had caught it by value. This is very similar to the following:
const std::vector<int>& rval_ref = return_vector();
except that in my rewrite you obviously can't use rval_ref
in a non-const manner.
Second example
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
In the second example you have created a run time error. rval_ref
now holds a reference to the destructed tmp
inside the function. With any luck, this code would immediately crash.
Third example
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
Your third example is roughly equivalent to your first. The std::move
on tmp
is unnecessary and can actually be a performance pessimization as it will inhibit return value optimization.
你的第三个例子大致相当于你的第一个例子。 tmp上的std :: move是不必要的,实际上可能是性能下降,因为它会抑制返回值优化。
The best way to code what you're doing is: 即直接返回temp值。
Best practice
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> rval_ref = return_vector();
I.e. just as you would in C++03. tmp
is implicitly treated as an rvalue in the return statement. It will either be returned via return-value-optimization (no copy, no move), or if the compiler decides it can not perform RVO, then it will use vector's move constructor to do the return. Only if RVO is not performed, and if the returned type did not have a move constructor would the copy constructor be used for the return.
First example2
考虑支持默认移动语义的类型T.还要考虑以下功能:
T f() {
T t;
return t;
}
T o = f();
1、在旧的C 03中,一些非最优编译器可能会调用复制构造函数两次,一个用于“返回对象”,另一个用于o。
2、在c 11中,由于f()中的t是一个左值,这些编译器可能像前面一样调用复制构造函数,然后调用o的move构造函数。
是否正确地说,避免第一个“额外副本”的唯一办法是移动t,当返回?
T f() {
T t;
return std::move(t);
}
只要return语句中的局部变量适合复制elision,它就绑定到右值引用,从而返回t;是相同的返回std :: move(t);在你的例子中相对于哪些构造函数是合格的。
注意,但是返回std :: move(t);防止编译器执行复制精度,同时返回t;不是,因此后者是优选的风格。 [感谢@Johannes的纠正。]如果复制精度发生,是否使用移动构造的问题成为一个问题。
参见标准中的12.8(31,32)。
还要注意,如果T有一个可访问的副本,但删除的移动构造函数,然后返回t;将不会编译,因为move构造函数必须先考虑;你必须说一些返回static_cast< T&>(t)的效果;使其工作:
T f()
{
T t;
return t; // most likely elided entirely
return std::move(t); // uses T::T(T &&) if defined; error if deleted or inaccessible
return static_cast<T&>(t) // uses T::T(T const &)
}
翻译自:
https://stackoverflow.com/questions/11817873/using-stdmove-when-returning-a-value-from-a-function-to-avoid-to-copy
参考:https://blog.youkuaiyun.com/csfreebird/article/details/45013813