C++ 返回值优化和构建结构的函数
我有一个函数可以“构建”一个要返回的结构:C++ 返回值优化和构建结构的函数,c++,c++11,move,rvo,C++,C++11,Move,Rvo,我有一个函数可以“构建”一个要返回的结构: struct stuff { int a; double b; Foo c; }; stuff generate_stuff() { Foo c = generate_foo(); //do stuff to Foo, that changes Foo: //... return {1, 2.0, c}; //should this be return {1, 2.0, move(c)};? }
struct stuff {
int a;
double b;
Foo c;
};
stuff generate_stuff() {
Foo c = generate_foo();
//do stuff to Foo, that changes Foo:
//...
return {1, 2.0, c}; //should this be return {1, 2.0, move(c)};?
}
我是否应该将c
移出函数?我意识到,通常,(N)RVO可以在适当的位置构建对象,但有时情况并非如此。什么时候不能执行(N)RVO,因此,什么时候应该移动函数的对象
换句话说,这显然是返回的临时文件的RVO。问题是,NRVO(名为返回值优化)会在
c
中发生吗?将c
构造到位(在函数的调用位置,在临时stuff
结构内部),或者将c
构造在函数中,然后复制到调用位置的结构中。对移动(c)
的调用不会将c移出函数,但将其移动到从函数返回的临时结构中。临时返回值应始终受益于RVO。然而,我相信将c移动/复制到临时文件中是无法优化的,因为c本身不是临时文件。因此,在这里,移动版本至少应该和复制版本一样高效(在使用g++、clang++和MVC++的简单场景中进行测试)
如果必须绝对减少复制/移动操作的数量,则可以编写
struct stuff {
int a;
double b;
Foo c;
};
stuff generate_stuff() {
stuff s{ 1, 2.0, generate_foo() };
//use s.c instead of c
//...
return s;
}
这将导致只有一个Foo的构造,并且由于NRVO,没有复制/移动
编辑:
正如@dyp在对您的问题的评论中指出的,材料的就地构造实际上不是RVO的情况,而是标准所要求的。无论如何,重要的一点是,不能省略
c
的移动/复制,因此使用move
不会导致性能损失。这构造了一个类型为stuff
的临时文件:它将保存c
的副本(作为左值,c
不能移动到此临时文件中)。然后这个临时对象本身可以移出函数,其Foo
成员(本身是c
的副本)将在那时被移动。如果Foo
包含内置类型,那么它不会有什么区别,但假设移动构造Foo
比复制构造它便宜,您应该使用std::move(c)
。复制省略允许在该实例中省略stuff
的复制/移动,但这不适用于构成stuff
的数据成员的构造。RVO仅适用于临时变量,如果要返回的表达式是名称,则NRVO仅适用于return语句。因此,都返回{1,2.0,generate_foo()}代码>和stuff s={1,2.0,generate_foo()};/*做点什么*/返回s代码>可以使用(N)RVO。@Praetorian:Foo可以假定不是POD@IgorTandetnik:所以,临时类型的stuff
将在呼叫站点(RVO)构建,问题是c
是否将在适当的位置构建,或者必须移动。不,这不是优化。标准要求返回{..}代码>直接初始化返回值。这不同于返回表达式代码>,请注意大括号的init列表不是表达式。@dyp:这与我所说的完全相反,或者我对英语的理解很差。