您现在的位置是:亿华云 > 应用开发
编译器之返回值优化
亿华云2025-10-08 23:35:58【应用开发】6人已围观
简介今天,借助本文,聊聊编译器的函数返回值优化。本文的主要内容如下图所示:函数返回机制既然本文的主题是返回值优化,那么就不得不提一下函数返回值在编译器中的实现机制,这样以便更好的理解本文内容。函数返回值的
今天,编译借助本文,值优聊聊编译器的编译函数返回值优化。
本文的值优主要内容如下图所示:
函数返回机制
既然本文的主题是返回值优化,那么就不得不提一下函数返回值在编译器中的编译实现机制,这样以便更好的值优理解本文内容。
函数返回值的编译传递分为两种情况:
当返回的对象大小不超过8字节时,通过寄存器(eax edx)返回
当返回的值优对象大小大于8字节时,通过栈返回。编译此处需要注意的值优时候,如果返回的编译是struct或者class对象,即使其大小不大于8字节,值优也是编译通过栈返回的。
在通过栈返回的值优时候,栈上会有一块空间来保存函数的编译返回值。当函数结束的时候,会把要返回的服务器租用对象拷贝到这块区域,对于内置类型是直接拷贝,类类型的话是调用拷贝构造函数。这块区域又称为函数返回的临时对象。
示例
为了能够方便通过输出理解程序的运行情况,本文中所有的代码示例均如下类所示:
class Obj {
public:
Obj() { // 构造函数
std::cout << "in Obj() " << " " << this << std::endl;
}
Obj(int n) {
std::cout << "in Obj(int) " << " " << this << std::endl;
}
Obj(const Obj &obj) { // 拷贝构造函数
std::cout << "in Obj(const Obj &obj) " << &obj << " " << this << std::endl;
}
Obj &operator=(const Obj &obj) { // 赋值构造函数
std::cout << "in operator=(const Obj &obj)" << std::endl;
return *this;
}
~Obj() { // 析构函数
std::cout << "in ~Obj() " << this << std::endl;
}
int n;
};
在本示例代码中
在各个函数中均加入了函数名称输出,以方便了解函数的调用情况各个函数中加入了对象指针地址输出,以方便了解构造、拷贝以及赋值等情况禁用优化
为了提升程序的性能,编译器在某些情况下,会对我们的代码进行优化,为了搞清楚编译都做了哪些优化,我们首先在禁用优化的情况下,看看程序的。
首先,我们看一段代码,如下:
Obj fun() {
Obj obj;
// do sth;
return obj;
}
int main() {
Obj obj = fun();
std::cout << "&obj is " << &obj << std::endl;
return 0;
}
现在,撇开编译器优化,我们单纯从上面代码进行分析,调用的Obj类成员函数的顺序应该为:
调用构造函数,站群服务器生成对象调用拷贝构造函数,生成临时对象析构第1步生成的对象调用拷贝构造函数,将第2步生成的临时变量拷贝到main()函数中的局部对象obj中调用析构函数,释放第2步生成的临时对象调用析构函数,释放main()函数中的obj局部对象为了验证我们所理解的顺序是否跟程序运行结果一致,编译并运行,结果如下:
g++ -g -std=c++11 test.cc -o test && ./test
in Obj() 0x7ffd6fb15240
&obj is 0x7ffd6fb15240
in ~Obj() 0x7ffd6fb15240
输出结果与我们预期差别很大,是不是怀疑之前的理解是错误的?其实这是因为编译器对函数返回值做了优化导致。
编译器提供了个编译选项-fno-elide-constructors来禁用返回值优化,编译并运行之后,输出如下:
g++ -std=c++11 -fno-elide-constructors -g test.cc -o test && ./test
in Obj() 0x7ffee18a9a00 // 在fun()函数中,构造obj对象
in Obj(const Obj &obj) 0x7ffee18a9a00 0x7ffee18a9a40 // 通过拷贝构造创建临时变量(fun()函数定义的obj--->临时对象)
in ~Obj() 0x7ffee18a9a00 // 析构fun()函数中构造的obj对象(fun()函数定义的obj)
in Obj(const Obj &obj) 0x7ffee18a9a40 0x7ffee18a9a30 // 通过拷贝构造函数构建obj(main函数中的)对象(临时对象--->main()函数定义的obj)
in ~Obj() 0x7ffee18a9a40 // 释放临时对象
&obj is 0x7ffee18a9a30
in ~Obj() 0x7ffee18a9a30 // 释放main()函数中定义的obj对象
上述输出结果跟我们之前的理解一致了吧
很赞哦!(7)