我了解RVO通常是可取的,但是如果不能应用RVO会怎样?具体来说,产生的汇编代码如何将本地类/结构实例返回给其调用者?
MyClass callee() {
MyClass a;
/* RVO is disabled */
return a;
}
void caller() {
/* RVO is disabled */
MyClass b = no_rvo();
}
在这种情况下,堆栈是什么样的? caller()
和callee()
是否分别为堆栈上的a
和b
分配空间,然后将a
复制到b
?如果是这样,callee()
末尾的RET语句是否将堆栈指针完全递减到以前的状态,还是在复制操作后释放a
的堆栈内存?
答案 0 :(得分:3)
这取决于调用约定。但是所有x86 32位和64位调用约定都做出相同的选择,并将指向返回值的指针作为“隐藏”的第一个arg传递。
callee
仍然可以优化a
(除非其他事情阻止了这种情况的发生),而直接将其存储在该返回值指针中即可。
非平凡可复制类型可能需要在某个时候运行copy-constructor,并运行a
的析构函数。
但是,关于:您的实际问题,启用优化功能后,调用方将传递&b
作为返回值指针。
在禁用优化的情况下,我想我已经看到一些编译器为单独的返回值临时创建空间,然后从那里进行复制,这对于琐碎可复制的类型来说是多余的。
理论上,返回值指针可以指向堆栈存储器以外的其他地方,例如如果分配给static MyClass arr[10]
的元素。
但是它不能指向callee
可以访问任何 other 方式的任何内容,因为在C ++抽象机中,返回值是一个单独的对象,在函数返回。