引用变量存储在何处

时间:2016-06-09 07:53:07

标签: c++ memory

我知道引用不会占用任何内存,它将指向它所引用的相同内存位置。 例如

int i=10;
int &r = a;

假设i指向内存位置1000,因此在这种情况下r也将指向内存位置1000。 但是在C ++中,当我们声明一个变量时,它将在某个位置存储在内存中。 在这种情况下,r指向某个位置,但它应该作为内部表示存储在内存中的某个位置,仅用于引用。 提前谢谢。

4 个答案:

答案 0 :(得分:6)

这是未指明的,并且有充分的理由。真正的答案是:它取决于参考。它可以表示为普通指针,或者根本不存在。

如果您有具有自动存储持续时间的功能本地参考,例如此r

void foo()
{
  int x[4] = {0, 1, 2, 3};
  int &r = x[1];
  // more code
}
然后它可能根本不会占用任何空间。编译器只会将r的所有用法视为x[1]的别名,并直接访问int。请注意,此类别名样式引用也可以来自函数内联。

另一方面,如果引用是“持久的”或对其他转换单元(例如数据成员或全局变量)可见,则它必须占用一些空间并存储在某处。在这种情况下,它很可能被表示为一个指针,使用它的代码将被编译为取消引用该指针。

理论上,其他选项也是可能的(例如查找表),但我不认为这些选项可供任何真实编译器使用。

答案 1 :(得分:3)

  

我知道引用不占用任何内存

不完全是。引用是否具有存储,未指定。它可能会也可能不会。在这个特定的例子中,它不需要存储,因此在典型的实现中,它不使用任何存储。

  

它将指向它引用的相同内存位置

这听起来像是重言式或只是误解,取决于你所说的“ point ”。引用引用到对象或绑定到对象。您可以将其视为变量名称的别名。变量名也不使用任何内存。

  

在这种情况下,r指向某个位置,但它应该存储在内存中的某处

它不需要存储在内存中。请考虑以下代码:

int i=10;
int &r = a;
int j = r * 3;

编译器可以将r * 3解释为i * 3,就像您首先编写的那样。引用对象的位置在编译时是已知的,因此不需要将地址存储在运行时的内存中。

但是,在其他情况下,可能需要存储。例如:考虑具有外部链接的非内联函数的引用参数。编译函数时无法知道引用的对象,因此必须在运行时将一些信息传递到内存中。

  

作为引用的内部表示仅使用const指针

这不正确。内部表示可能使用指针,或者它可能使用其他东西,或者它可能不需要使用任何东西。

所以,简明扼要地回答

  

参考变量存储在哪里

未指明。无处或无处。

答案 2 :(得分:0)

标准说:

  

未指明引用是否需要存储(3.7)。

(C ++ 11,[dcl.ref]¶4)

这意味着编译器可以根据具体情况自行选择是否需要任何存储。

现在,让人们说出他们想要的东西,但引用归结为指针的语法糖(即使在编译器级别,在所有主要的C ++编译器中,“参考”概念几乎在前端后立即消失);因此,在一般情况下,它们可能需要它们在内存中的空间,就像指针一样。但是,在像您这样的情况下(本地引用),编译器应该透视它们并根据需要对它们进行优化。

请注意,这不是引用的排他性 - 编译器甚至可以通过指针执行相同类型的优化(一旦您的代码以SSA形式进行,即使引用无法重新安装,也没有什么特别之处)

此:

int glob;

void direct() {
    glob = 16; 
}

void through_reference() {
    int &a = glob;
    a = 16;
}

void through_pointer() {
    int *a = &glob;
    *a = 16;
}

总是归结为我在gcc.godbolt.org上尝试的任何编译器上的相同代码 - example

direct():
        mov     DWORD PTR glob[rip], 16
        ret
through_reference():
        mov     DWORD PTR glob[rip], 16
        ret
through_pointer():
        mov     DWORD PTR glob[rip], 16
        ret
glob:
        .zero   4

另一方面,谈论结构时,情况会变得更加滑溜;这里允许编译器从结构的实际布局中删除引用(如果它能够重构它们实际指向的内容),而对于指针,情况可能会稍微复杂一些(它们的省略会破坏标准布局类)内容)。

实际上,我从未真正看到过在任何实际编译器中实现的这种优化。拿gcc或MSVC或Clang等等,你总会看到结构大小等于even in the most trivial cases

答案 3 :(得分:0)

  

作为引用的内部表示仅使用const指针

你在哪里听到的?事实并非如此。

标准没有规定如何实施参考。

以下是过度简化

最常见的是,编译器在内部有一个符号表,它存储了变量所需的所有信息。

让我们来看一个简单的案例:

int a;
a = 100;

然后编译器可以有这样的东西(为简单起见,让a的地址成为固定的已知地址)

| identifier | type | address  |
|------------|------|----------|
| a          | int  | 0xFF00A4 |

然后它可以将c ++代码转换成这样的代码:

mov 0xFF00A4, 100

让我们在混音中添加一个引用:

int a;
a = 100;
int& ra = 300;

编译器具有的符号表:

| identifier | type | address  |
|------------|------|----------|
| a          | int  | 0xFF00A4 |
| ra         | int& | 0xFF00A4 |

或者:

| identifier | type | address  | alias |
|------------|------|----------|-------|
| a          | int  | 0xFF00A4 | -     |
| ra         | int& | -        | a     |

因此可以生成如下代码:

mov 0xFF00A4, 100
mov 0xFF00A4, 300

如果函数中有引用参数,则会在内部传递指针。