c++11:函数内部返回对象使用move语义

本文深入探讨C++11中的move语义和返回值优化(RVO),解释如何在函数返回中有效利用这些特性,避免不必要的复制。文章对比了几种返回局部变量的方法,并强调了最佳实践,即直接返回局部变量,让编译器选择最优的优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一句话,直接返回即可,一般不用任何特殊写法。

      当启动了c++11选项后,通过函数返回代码没有发生任何变化,但是已经使用了move语义,而不一定使用之前介绍的NRVO编译器优化技术。

注意,右值引用rvalue reference是表达式计算完成后就不再存在的临时变量,左值是表达式计算完成后的变量。如果能够用&求址的,就是左值。

下面是stackoverflow上的一个讨论贴,比较有价值:

结论是:

1. 应该按照正常写法(Best Practice)返回local 变量

2. 编译器会决定要么使用NRVO,要么使用Move语义来优化返回语句

    如果使用条件语句返回,会抑制编译器使用NRVO

    也不要将返回的值包装在另一个函数中返回,而应该仅仅返回local变量

    如果要返回一个local变量内的成员变量,需要显式的使用move

3. 如果使用Move语义,需要返回的类型有move constructor,否则只会进行复制

 

https://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值