C++做引用占用内存
C++ do references occupy memory
我读到引用只是符号 table 中存在的变量的别名。考虑以下代码
int main()
{
int y = 6;
int &z = y;
int k = 43;
test(2,y,5,78);
cout << &y << "\n";
cout << &z << "\n";
cout << &k << "\n";
}
void test(int a,int & x, int g, int h)
{
cout << &a << "\n";
cout << &x << "\n";
cout << &g << "\n";
cout << &h << "\n";
}
对于我得到的输出
0039F740
0039F848
0039F748
0039F74C
0039F848
0039F848
0039F830
如果reference在栈中没有占用内存,为什么会偏移内存。例如。在函数测试中,局部变量a在0039F740,g在0039F748。 g 不应该在 0039F744 吗?
有人可以深入解释一下吗?
您的函数有四个参数。
每个参数都必须传递给函数。
其中一个参数是引用这一事实并没有改变这个基本事实。您看到的附加 space 是函数的引用参数。
在这种情况下,引用实际上只是伪装的指针。当您在本地范围内引用本地范围内的对象时,大多数 C++ 编译器实际上会将其优化,以便该引用不会占用任何实际内存。
但是函数调用是一种全新的球类游戏。该函数期望接收对某个对象的引用。该函数无法通过心灵感应知道作为参考传递给它的是什么。无论调用该函数的是什么,都负责提供引用参数。不用说,传递该信息需要几个字节,即作为引用传递的对象的地址(我最近提到过关于指针的事情吗?)
如果函数是在 static
范围内声明的(无外部链接),并且为编译选择了足够积极的优化级别,那么您的 C++ 编译器肯定会内联函数调用,并且能够优化参考参数。
但是声明带有外部链接的函数通常会导致编译器懒得尝试内联函数调用。它将继续并生成一个成熟的独立函数,该函数期望拥有它有权使用的每个参数。
以更笼统的方式回答您的问题:C++ 标准不要求引用应该占用内存,但也不要求它们不应该占用内存。 C++ 编译器可以自由地以任何方式编译代码,只要结果是正确的,并且符合预期。如果在特定情况下,C++ 编译器想出如何优化引用,使其实际上不 "exist" 作为其自身的离散对象,则可以自由地这样做。但这不是必需的。
引用比"aliases to something else in the symbol table"更复杂。实际上,该定义通常甚至不适用。例如,一个引用参数不能只是 "something else in the symbol table" 的别名,因为那样会阻止使用多个不同的参数值调用该函数。
标准没有说明你应该怎么做,但引用的典型实现是只使用指针。如果您有 int& x
,则 x
returns *(pointer)
和 &x
returns (pointer)
。指针确实占用内存,但没有明确定义的 C++ 操作会泄露支持引用的指针的存储位置。
请注意,除非您需要使用自动存储 ("on the stack") 获取对象的地址,否则编译器不需要实际将其放入堆栈。它可以完全存在于寄存器中,也可以完全优化掉。例如,使用此函数:
int foo(int a, int b) { return a + b; }
On x86_64 System V调用约定,a
传入rdi寄存器,b
传入rsi
寄存器,计算结果在 rax
中,函数不需要为它的任何值触及堆栈。
我读到引用只是符号 table 中存在的变量的别名。考虑以下代码
int main()
{
int y = 6;
int &z = y;
int k = 43;
test(2,y,5,78);
cout << &y << "\n";
cout << &z << "\n";
cout << &k << "\n";
}
void test(int a,int & x, int g, int h)
{
cout << &a << "\n";
cout << &x << "\n";
cout << &g << "\n";
cout << &h << "\n";
}
对于我得到的输出
0039F740
0039F848
0039F748
0039F74C
0039F848
0039F848
0039F830
如果reference在栈中没有占用内存,为什么会偏移内存。例如。在函数测试中,局部变量a在0039F740,g在0039F748。 g 不应该在 0039F744 吗?
有人可以深入解释一下吗?
您的函数有四个参数。
每个参数都必须传递给函数。
其中一个参数是引用这一事实并没有改变这个基本事实。您看到的附加 space 是函数的引用参数。
在这种情况下,引用实际上只是伪装的指针。当您在本地范围内引用本地范围内的对象时,大多数 C++ 编译器实际上会将其优化,以便该引用不会占用任何实际内存。
但是函数调用是一种全新的球类游戏。该函数期望接收对某个对象的引用。该函数无法通过心灵感应知道作为参考传递给它的是什么。无论调用该函数的是什么,都负责提供引用参数。不用说,传递该信息需要几个字节,即作为引用传递的对象的地址(我最近提到过关于指针的事情吗?)
如果函数是在 static
范围内声明的(无外部链接),并且为编译选择了足够积极的优化级别,那么您的 C++ 编译器肯定会内联函数调用,并且能够优化参考参数。
但是声明带有外部链接的函数通常会导致编译器懒得尝试内联函数调用。它将继续并生成一个成熟的独立函数,该函数期望拥有它有权使用的每个参数。
以更笼统的方式回答您的问题:C++ 标准不要求引用应该占用内存,但也不要求它们不应该占用内存。 C++ 编译器可以自由地以任何方式编译代码,只要结果是正确的,并且符合预期。如果在特定情况下,C++ 编译器想出如何优化引用,使其实际上不 "exist" 作为其自身的离散对象,则可以自由地这样做。但这不是必需的。
引用比"aliases to something else in the symbol table"更复杂。实际上,该定义通常甚至不适用。例如,一个引用参数不能只是 "something else in the symbol table" 的别名,因为那样会阻止使用多个不同的参数值调用该函数。
标准没有说明你应该怎么做,但引用的典型实现是只使用指针。如果您有 int& x
,则 x
returns *(pointer)
和 &x
returns (pointer)
。指针确实占用内存,但没有明确定义的 C++ 操作会泄露支持引用的指针的存储位置。
请注意,除非您需要使用自动存储 ("on the stack") 获取对象的地址,否则编译器不需要实际将其放入堆栈。它可以完全存在于寄存器中,也可以完全优化掉。例如,使用此函数:
int foo(int a, int b) { return a + b; }
On x86_64 System V调用约定,a
传入rdi寄存器,b
传入rsi
寄存器,计算结果在 rax
中,函数不需要为它的任何值触及堆栈。