C++ c++;11返回值优化还是移动?
我不明白什么时候应该使用C++ c++;11返回值优化还是移动?,c++,c++11,move,return-value-optimization,rvo,C++,C++11,Move,Return Value Optimization,Rvo,我不明白什么时候应该使用std::move,什么时候应该让编译器优化。。。例如: using SerialBuffer = vector< unsigned char >; // let compiler optimize it SerialBuffer read( size_t size ) const { SerialBuffer buffer( size ); read( begin( buffer ), end( buffer ) ); // Ret
std::move
,什么时候应该让编译器优化。。。例如:
using SerialBuffer = vector< unsigned char >;
// let compiler optimize it
SerialBuffer read( size_t size ) const
{
SerialBuffer buffer( size );
read( begin( buffer ), end( buffer ) );
// Return Value Optimization
return buffer;
}
// explicit move
SerialBuffer read( size_t size ) const
{
SerialBuffer buffer( size );
read( begin( buffer ), end( buffer ) );
return move( buffer );
}
使用SerialBuffer=vector;
//让编译器优化它
串行缓冲区读取(大小)常量
{
串行缓冲区(大小);
读取(开始(缓冲区),结束(缓冲区));
//收益值优化
返回缓冲区;
}
//显式移动
串行缓冲区读取(大小)常量
{
串行缓冲区(大小);
读取(开始(缓冲区),结束(缓冲区));
返回移动(缓冲);
}
我应该使用哪一个?所有返回值要么已经移动了
,要么已经优化了,因此不需要使用返回值显式移动
编译器可以自动移动返回值(优化拷贝),甚至优化移动
n3337标准草案第12.8节(C++11):
当满足某些条件时,允许实现省略
类对象的复制/移动构造,即使复制/移动
对象的构造函数和/或析构函数有副作用。在里面
在这种情况下,实现将处理
省略了复制/移动操作,仅作为两种不同的引用方式
对于同一对象,该对象的销毁发生在
后来这两个物体会被摧毁
没有优化。这省略了复制/移动操作,
在下列情况下,允许复制省略
(可组合使用以消除多个副本):
[……]
例如:
在这里,省略的条件可以组合起来,以消除对类Thing
的复制构造函数的两个调用:
将本地自动对象t
复制到函数f()返回值的临时对象中
并将该临时对象复制到对象t2
。有效地,本地对象的构造t
可以视为直接初始化全局对象t2
,并且该对象的销毁将在程序中发生
出口将move构造函数添加到Thing
具有相同的效果,但它是来自
被省略的t2
的临时对象。-[结束示例]
当满足或将满足省略复制操作的条件时,除了源
对象是函数参数,要复制的对象由左值指定,重载分辨率为
选择首先执行复制的构造函数,就像对象由右值指定一样。如果过载
解析失败,或者所选构造函数的第一个参数的类型不是对的右值引用
对象的类型(可能是cv限定的)重载解析将再次执行,并将对象视为
左值
如果要返回局部变量,请不要使用move()
。这将允许编译器使用NRVO,如果没有,编译器仍然可以执行移动(局部变量在return
语句中变为R值)。在该上下文中使用move()。如果您返回的不是局部变量,那么NRVO无论如何都不是一个选项,如果(且仅当)您打算窃取对象,则应使用move()
。仅使用第一种方法:
Foo f()
{
Foo result;
mangle(result);
return result;
}
这已经允许使用move构造函数(如果有)。事实上,当允许复制省略时,局部变量可以精确地绑定到return
语句中的右值引用
您的第二个版本主动禁止复制省略。第一个版本普遍更好。非常简单
返回缓冲区代码>
如果你这样做,那么要么NRVO会发生,要么不会。如果没有发生,则将从中移动缓冲区
返回std::move(缓冲区)代码>
如果您这样做,那么NVRO将不会发生,并且缓冲区将从中移动
因此,在这里使用std::move
没有任何好处,也会有很多损失
上述规则有一个例外*:
如果buffer
是右值引用,则应使用std::move
。
这是因为引用不符合NRVO的条件,因此没有
std::move
它将导致从左值复制
这只是规则“始终move
rvalue引用”的一个实例
和转发
通用参考”,优先于
规则“从不移动<代码>返回值”
*从C++20开始,这个异常可以被忘记。return
语句中的右值引用现在被隐式地从中移除了。从我迄今为止的阅读来看,普遍的共识似乎是使用RVO而不是显式地使用move
的编译器:现代编译器足够聪明,几乎在任何地方都可以使用RVO,而且它比move
更高效。但请注意,这只是“道听途说”,所以我对一个有文档记录的解释很感兴趣。局部变量函数返回值永远不需要显式移动。它隐式地移动到那里。然后编译器可以自由选择:如果可能,它将使用RVO,如果不可能,它仍然可以移动(如果类型不可能移动,它将进行复制)。@MartinBa,never say never;)如果局部变量的类型与返回类型不同,则需要显式移动,例如std::unique_ptr f(){auto p=std::make_unique();p->foo();return p;}
,但如果类型相同,则可能会移动(该移动可能会被省略),@JonathanWakely所说的已经在缺陷报告和
Foo f()
{
Foo result;
mangle(result);
return result;
}
Buffer read(Buffer&& buffer) {
//...
return std::move( buffer );
}