C++返回局部变量的引用

问题一:
返回一个局部变量的引用。如:
int& ABC()
{
int n = 5;
return n;
}
void main()
{
int x;
x=ABC();
cout<<x<<endl;
}
为什么这里能接收到 返回局部变量的引用呢?局部变量n没有被销毁吗?
我实验过了。
问题二:
局部对象这样也可以接收到。如下面这个程序:
#include <iostream>
using namespace std;

class Complex
{
public:
Complex(double r=0,double i=0)
{
real=r;imag=i;
}
Complex(const Complex& c);
Complex& operator+(Complex &);
void display( );
private:
double real, imag;
};
Complex::Complex(const Complex& c)
{
real=c.real;
imag=c.imag;
}
Complex& Complex::operator+(Complex &c2)
{
int a=1;
Complex c;
c.real=real+c2.real;
c.imag=imag+c2.imag;
return c;
}
void Complex::display( )
{
int xxxx=1;
cout <<"(" <<real <<"+" <<imag <<"i)" <<endl;
}

int main( )
{
double x, y;
cin>>x>>y;
Complex comp1(x,y),comp2(y,x),comp3;
comp1.display( );
comp2.display( );

comp3=comp1.operator+(comp2); //用对象 接收函数返回的引用
Complex& p=comp1.operator+(comp2); //用对象的引用 接收函数返回的引用

p.display();
comp3.display();
return 0;
}

这里 《用对象 接收函数返回的引用》和《用对象的引用 接收函数返回的引用》结果是不同的,一个被释放了。另一个没有被释放。为什么?用不同的
类型接收 局部对象的引用有什么区别吗?不要说《用对象 接收函数返回的引用》 会调用拷贝构造函数。我设了断点看了。没有进入拷贝构造函数。
而且很奇怪的现像是: 对于局部对象C的地址&C和《用对象 接收函数返回的引用》的对象comp3地址不同。。。 不理解《用对象接收 函数返回的引用》内部是怎样运作 的?
int& ABC()
{
int n = 5;
return n;
} 如何实现 能让 int x=ABC()结果变?请举个例子

对于赋值。comp3=comp1.operator+(comp2);
如何实现 也能让 comp3变随机值? 举例说明。。

看不到不正常 我以后就这么用 返回临时变量的引用了。。。。

1,所谓不能返回局部变量,是指局部变量在栈空间中分配内存,函数返回时栈指针回退,当主调函数继续调用其它被调函数时,栈指针上移,上一次函数调用所分配的空间会被本次调用覆盖,如果此时再引用原来的局部变量就会出现不可预见的结果。
所以局部变量在函数返回时并不是被销毁而是相当于可被再次利用。
所以如果第一题你在cout<<x<<endl;前调用一函数,此函数大量分配局部变量,后面的输出值必变!

2。第二题要明确构造函数是在对象构造时调用的,而不是在对象间相互赋值时调用的,你的comp3在对象在申明时已经调用了Complex(double r=0,double i=0).如果你这样写:" Complex comp3=comp1.operator+(comp2); //用对象 接收函数返回的引用" 则拷贝构造函数必被调用到。
所以这样对于"局部对象C的地址&C和《用对象 接收函数返回的引用》的对象comp3地址不同。。。 "应该理解的吧。

补充:向你这样把返回的引用赋给变量是无论怎么都不会变的,因为返回时进行了变量的复制(不一定是调用构造函数),要改变其实我上面已经说了只要在cout<<X前调用一个函数且函数内定义了局部变量即可:
int &x= ABC(); //必须定义成引用
test();
cout<<x;

void test()
{
int a=8;
}
这样X的输出将是8,下题类似不再举例.
温馨提示:答案为网友推荐,仅供参考
第1个回答  2010-05-21
第一个问题:
函数退出时局部变量出栈,对象肯定是销毁了。

销毁指的是将那块内存标为空闲供其它变量使用,而该内存上的值仍然存在。

释放后那块内存并不是马上就被其他地方占用,根据实际情况起码会空闲一会,可能是一瞬间。如果你的程序较复杂,那这块内存可能很快就再次被使用,如果程序很简单,可能在很长一段时间内都是空闲。

所以在函数返回后将变量的值马上赋值给另外一个变量,局部变量已经销毁了,这块内存上的值还没来得及被修改,所以你的外部变量获得了一个正确的值。

所以你的结果正确并不代表变量没有被销毁。无论用引用还是变量来接受局部变量的值,局部变量肯定是已经销毁了的。

第二个问题:
用引用和用对象的区别在于,引用只是个别名,类似指针(引用在C++底层其实就是指针),而对象需要构造。

你的局部变量跟接受值的外部变量是两个变量,分配在不同的栈上,所以肯定有两个不同的地址了。

比如,
引用:
MyClass& x = func();
这个只是将引用指向func()返回的变量。

对象:
分两种情况:
MyClass x = func();
这种情况调用的是MyClass的拷贝构造函数给x赋的值。
MyClass x;
x = func();
这种情况调用的是MyClass的operator=给x赋的值。

你可以自己写个类,在它的拷贝构造函数或operator=函数返回前加很多乱七八糟的代码,等函数返回后再看成员变量的值是否还正常,有很大几率是个随机值。
第2个回答  2010-05-21
1、
调用函数时,向操作系统申请栈空间,函数返回时,栈空间被回收,就好比你向房东租房子,退房后,房子里面的东西(栈空间的变量)或许不变,或许物是人非,但你无权过问

2、先了解什么叫拷贝函数,什么叫拷贝构造函数
如何实现 也能让 comp3变随机值? 举例说明。。
倘若其它进程或线程或就是本进程的某个操作刷写了该地址的内容,那结果就是错误的。使用权不在你,操作系统无义务向你确保不改变该地址空间的内容
第3个回答  2010-05-21
1:n值肯定是被销毁了,=将返回值的引用赋给x然后销毁n,栈上肯定是没有n的数据了。
Complex& p=comp1.operator+(comp2);这么使用本身就是错的,引用就是一个别名,那句执行完之后的话p是栈上一个已经析构了complex对象的一个别名,结果肯定是不对的
第4个回答  2010-05-21
两个问题的原理一样。
第一个程序,你用下面的程序做下比较
int& ABC()
{
int n = 5;
cout << *n << endl; // 这里打印出n的内存地址,假设是 0001
return n;
}
void main()
{
int x;
x=ABC(); // 执行函数,打印0001
cout<<*x<<endl; // 这里打印出n的内存地址, 你会发现打印出来的结果是0002。
int& y = ABC(); // 执行函数,打印0001
cout << *y << endl; // 打印y的地址,你会发现打印的结果一热是0001
}

第二个程序,使用同样的方法测试下
要修改的地方有:
display函数中语句改成下面的语句
cout <<"(" <<*real <<"+" <<*imag <<"i)" <<endl;
Complex& Complex::operator+(Complex &c2)函数中在return之前加一句
c.display();
执行,你会发现,comp3.display() 得到的结果与c.display()得到的结果不同。
而p.display()得到的结果越与c.display() 得到的结果是相同的。

原理:
使用语句 Complex& p 会调用构造函数,因为这样写在编译器看来p只是一个别名(也就是对象的引用),没有分配另外分配内存。而Complex comp3 则不同,在编译器看来,comp3是一个需要特别为其分配另外的内存空间的变量(也就是对象)。
利用返回引用类型的函数为p和comp3说白了,对p的赋值就是为局部变量的内存空间其别名p,而对comp3就是将局部变量的值赋给comp3。而由于局部变量在函数执行完毕后会被回收内存空间。因此,p指向的内存被销毁,值就变了。

注意:
用下面的语句会发生编译错误 error C2530: “p”: 必须初始化引用
int& p;
相似回答