我有一个函数可以“构建”一个要返回的结构:
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,因此,什么时候应该 move 函数的对象?
换句话说,这显然是返回的临时对象的 RVO。问题是,c
会发生 NRVO(命名返回值优化)吗? c
是就地构造(在函数的调用点,临时 stuff
结构内),还是 c
构造在函数,然后复制到调用站点的结构中。
最佳答案
您对 move(c)
的调用并不是将 c 移出函数,而是将其移入从函数返回的临时结构中。临时返回值应始终受益于 RVO。但是,我相信 c 到临时的 move/复制不能被优化掉,因为 c 本身不是临时的。所以在这里 move 版本应该至少和复制版本一样高效(测试了 g++、clang++ 和 MVC++ 的简单场景)。
如果你必须绝对减少复制/move 操作的数量,那么你可以写
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;
}
由于 NRVO,这只会导致 Foo 的单一构造,并且没有复制/move 。
编辑:
正如@dyp 在对您的问题的评论中指出的那样,Stuff 的就地构造实际上并不是 RVO 的情况,而是标准所要求的。无论如何,重要的部分是不能省略 c
的 move/复制,因此使用 move
永远不会导致性能下降。
关于c++ - 返回值优化和构建结构的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28953854/