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:这与我所说的完全相反,或者我对英语的理解很差。