int power(int x) { return x * x; } int main() { int x = power(2); //cout << v.str[0] << endl; return 0; }
对于返回值比较偏小的函数,直接将返回值保存至寄存器。
这里先将x的值保存至eax中,在用imul指令计算x*x的值(eax = eax * x)。函数返回后直接从eax中取回结果。
如果结果比较大,无法将结果保存至寄存器中,那只能将结果的地址保存至寄存器中。
struct Node { char str[100]; }; Node fun() { Node n; n.str[0] = 'o'; return n; } int main() { Node x = fun(); return 0; }
首先观察fun函数返回的过程:
使用rep movs将n按字节拷贝至rbp+170h的地址(拷贝的长度由ecx决定),将返回的地址保存至rax中。
再看获取fun返回值的过程:
将返回的地址从rax中取出,再拷贝至x中。
也就是说这个过程将返回的结构体拷贝了2次。。。从n拷贝到temp,再从temp拷贝到x。
在C++11中提供了RVO/NRVO机制可以防止这种重复拷贝开销。另一种是RVO/NRVO机制实现复制消除机制。
RVO机制使用父栈帧(或任意内存块)来分配返回值的空间,来避免对返回值的复制。也就是将Base fun();改为void fun(Base &x);
Base fun(int n) { return Base(); } Base x = fun();
这段代码输出为:
Base()
~Base()
但如果代码产生了改动,编译器无法知道应该防止哪个对象作为返回值,就无法触发RVO机制:
Base fun(int n) { Base a,b; if (n % 10 == 1) { return a; } else { return b; } }