Dan*_*len 10 c++ compiler-construction
我通常理解函数如何按值返回对象.但我想在较低的层面上理解它.装配水平如果合理.
我理解这段代码
ClassA fun(){
ClassA a;
a.set(...);
return a;
}
Run Code Online (Sandbox Code Playgroud)
在内部转化为
void fun(Class& ret){
ClassA a;
a.set(...);
ret.ClassA::ClassA(a);
}
Run Code Online (Sandbox Code Playgroud)
这有效地在返回值上调用复制构造函数.
我也明白,有一些优化(如NRVO)可以生成以下代码,避免复制构造函数.
void fun(Class& ret){
ret.set(...);
}
Run Code Online (Sandbox Code Playgroud)
不过我的问题有点基础.它与具体的对象无关.它甚至可以是原始类型.
让我们说我们有这个代码:
int fun(){
return 0;
}
int main(){
fun();
}
Run Code Online (Sandbox Code Playgroud)
我的问题是存储在内存中的返回对象在哪里.
如果我们看一下堆栈......有堆栈框架main然后是堆栈框架fun.返回对象是否存储在某个地址中,可能在两个堆栈帧之间?或者它可能存储在main堆栈帧中的某个地方(可能是生成的代码中通过引用传递的地址).
我已经考虑过了,第二个似乎更实用但是我不明白编译器如何知道在堆栈帧中推送多少内存main?它是否计算出最大的返回类型是什么,即使存在浪费的内存也会推动它?或者它是动态完成的,它仅在调用函数之前分配该空间?
Sam*_*hik 15
C++语言规范没有指定这些低级细节.它们由每个C++实现指定,实际的实现细节因平台而异.
几乎在所有情况下,返回值都是一个简单的本机类型,它返回到某个指定的CPU寄存器中.当函数返回类实例时,细节会有所不同,具体取决于实现.有几种常见的方法,但典型的情况是调用者负责在调用函数并将其他隐藏参数传递给函数之前为堆栈上的返回值分配足够的空间,函数将复制到该函数返回值(或者在RVO的情况下构造它).或者,参数是隐式的,并且函数可以在调用的堆栈帧之后在堆栈上找到返回值本身的空间.
给定的C++实现也可能仍然使用CPU寄存器来返回足够小的类以适合单个CPU寄存器.或者,也许,一些CPU寄存器被保留用于返回稍大的类.
详细信息各不相同,您需要查阅C++编译器或操作系统的文档,以确定适用于您的特定详细信息.
答案是ABI特定的,但通常调用是使用隐藏参数编译的,该参数是指向函数应该使用的内存的指针,就像你说的那样假设函数被编译为
void fun(Class& ret){
ClassA a;
a.set(...);
ret.ClassA::ClassA(a);
}
Run Code Online (Sandbox Code Playgroud)
然后在呼叫站点你会有类似的东西
Class instance = fun();
fun(instance);
Run Code Online (Sandbox Code Playgroud)
现在,这使得调用者sizeof(Class)在堆栈上保留字节并将该地址传递给该函数,以便fun"填充"该空间.
这与调用者的堆栈帧如何为其自己的本地保留空间没有什么不同,唯一的区别是传递给其中一个本地的地址fun.
请注意,如果sizeof(Class)小于寄存器(或几个寄存器)的大小,则完全有可能直接在其中返回值.