引用是否在C ++中占用内存?

时间:2012-01-13 05:49:23

标签: c++ pointers reference

我已经阅读了很多关于这个问题的文章,我从中得到的引用只是别名而且它们不消耗任何内存。编译器用指向变量的地址替换引用。

任何人都可以解释下面的例子会发生什么。编译器如何使用参考ri?

int main()
{  
    int *pi = new int(50);
    int &ri = *pi;
    ri = 30;
    cout << "val = " << ri << " , " << *pi << endl;
}

它给了我输出:

val = 30  ,   30

6 个答案:

答案 0 :(得分:3)

int *pi = new int(50);

       +----+
pi --> | 50 |
       +----+


int &ri = *pi;

        +----+
pi  --> | 50 |    ri = 50, same as *pi, which is 50
        +----+

ri = 30;      now the contents of what pi points to i.e. *pi is replaced with 30

        +----+
pi  --> | 30 |
        +----+

答案 1 :(得分:2)

编译器可能将引用替换为实际对象:

int main()
{  
    int *pi = new int(50);
    //int &ri = *pi; //compiler might remove this

    *pi = 30; //then it replaces ri with *pi 

    cout << "val = " << *pi << " , " << *pi << endl; //here as well
}

这是编译器可能做的一件事。

答案 2 :(得分:1)

int *pi = new int(50);

你分配一个int对象50;

int &ri = *pi;

你设置一个别名ri到这个int对象,ri是这个对象,pi是对象的地址;

ri = 30;

将30重新分配给int对象;记得ri是int对象;

cout << "val = " << ri << " , " << *pi << endl;

ri和* pi是同一个对象。 您只记得一个对象可能有很多别名,并且使用这些别名中的任何一个都可以操纵该对象。

以及删除的位置。

答案 3 :(得分:1)

引用被定义为别名。标准没有具体说明它们的表示方式,尽管实现方式变化不大。基本上:

  • 在一般情况下,引用是引擎盖下的对象地址(如指针)
  • 只要有可能,编译器就会努力消除间接

让我们看看它是如何翻译的,从你的程序开始:

int main()
{  
    int *pi = new int(50);
    int &ri = *pi;
    ri = 30;
    std::cout << "val = " << ri << " , " << *pi << std::endl;
}

我们可以消除ri,因为它绑定的对象是编译器已知的:

int main()
{  
    int *pi = new int(50);
    *pi = 30;
    std::cout << "val = " << *pi << " , " << *pi << std::endl;
}

我们可以消除*pi,因为编译器知道它的最终值:

int main() {
  new int(50); // stupid possible side effect usually forbid to optimize this out
  std::cout << "val = " << 30 << " , " << 30 << std::endl;
}

我会注意到,在您的示例中,new调用完全没用,您还可以引用尚未动态分配的对象。

int main() {
  int i = 50;
  int& ri = i;
  ri = 30;
  std::cout << "val = " << ri << " < " << i << std::endl;
}

同样有效,没有内存泄漏。


回到表示之间的区别:

void swap(Foo& left, Foo& right);

通常实现为:

void swap(Foo* left, Foo* right);

在这种情况下,引用最终占用(某些)空间(与指针一样多)。

另一方面:

class Object {
public:
  Object(): foo(f), f() {}

  Foo const& foo;

  void set(Foo const& value);

private:
  Foo f;
};

编译器通常foo运行时表示。它是const引用的事实将用于将f上调用的可能方法限制为不更改它的方法(语义差异),但在运行时它们将直接传递f

答案 4 :(得分:0)

ri是一个堆栈变量,就像一个无法分配给新内存地址的指针一样。它主要是一个语义糖,没有什么可以用你不能用指针做的参考你可以做得更安全。当此函数终止时,ri使用的空间将从堆栈中清除。

答案 5 :(得分:0)

引用变量占用堆栈内存,测试它的最佳方法是使用c ++程序的程序集,如下所示.... 编写如下所示的c ++程序并生成它的程序集

#include<iostream>
using namespace std;

int main(){
int i = 100;
int j = 200;
int &x1 = i;
int &x2 = i;
int &x3 = i;
int &x4 = i;
int &x5 = i;
int &x6 = i;
int &x7 = i;

cout << "reference value" << x1 << endl;
return 0;

}

此程序的组装显示堆栈指针向下移动到36字节&#34;这意味着引用获取内存&#34;。

main:
.LFB966:
.cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl   %ebx
    andl    $-16, %esp
    subl    $64, %esp   
    movl    $100, 28(%esp)

上面的指令(subl $ 64,%esp)是堆栈指针移动,为堆栈上的i,j和七个引用变量(x1到x7)分配空间。

如果您更改上面的cpp程序

#include<iostream>
using namespace std;

int main(){
int i = 100;
int j = 200;
int &x1 = i;
cout << "ref changed" << x1 << endl; 
return 0;
}

它的组装显示堆栈指针移动12个字节..

main:
.LFB966:
   .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl   %ebx
    andl    $-16, %esp
    subl    $32, %esp 
    movl    $100, 20(%esp)

以上说明&#34; subl $ 32,%esp&#34;堆栈指针移动,为堆栈上的i,j和x1引用变量分配空间

我相信上面的实际可以清除所有事情,如果我错了,请纠正我...... :)