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

zhuanmentiwen 2010-06-22 09:38:00
在好多地方都看到,要避免返回局部变量的引用,因为函数执行完毕后,局部变量将会被销毁,返回引用比较危险。
请按下面的示例:

#include<iostream>
using namespace std;

int& func()
{
int m=9;
return m;
}
int main()
{
int fp=func();

cout<<fp<<endl;

return 0;
}

在上面的代码中,函数func()返回了局部变量m的引用,func()执行完后,按照我的理解,m将被销毁,那么结果输出的fp应该不是9吧。
可能我对C++的引用理解还有误,那么请看下面的返回局部变量指针的例子。

#include<iostream>
using namespace std;

int* func()
{
int m=9;
return &m;
}
int main()
{
int *fp=func();

cout<<*fp<<endl;

return 0;
}

为什么结果仍然是输出9呢?
最近被C++的内存管理搞晕了,大家有好的资料或者书籍文档推荐下,谢谢了。
...全文
1197 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
yinhanng 2010-08-23
  • 打赏
  • 举报
回复
自己试了一下:
int& func()
{
int m=9;
return m;
}
int value = func();
取里面m的地址与value的地址, 其实是不一样的,
再试了一个自己实现的对象:
yh& fun( )
{
yh y1;
return y1;
}
yh y2 = fun();
y1 与y2的地址也是不一样的, 而且当y1返回后调用了yh的复制构造函数, 是否编译器做了优化就不清楚了.
s1418252 2010-07-20
  • 打赏
  • 举报
回复
学习了。
我在编译的时候遇到了这样的问题,自己无法解释,还望高人指点。
int& func()
{
int m=9;
return m;
}
是有问题的,正如大家解释的那样。
static int& func1()
{
int a = 10;
return a;
}
在和int& func()同样的情况下,是没有问题的,我不明白。
tjyjx7946358 2010-06-22
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 brookmill 的回复:]
引用楼主 zhuanmentiwen 的回复:
在好多地方都看到,要避免返回局部变量的引用,因为函数执行完毕后,局部变量将会被销毁,返回引用比较危险。

函数返回之后,m所在的内存就有可能给其他函数使用,他的值就不可靠了。
象楼主给的那段代码,m所在的内存刚好没有别人用过,所以值还没变。
[/Quote]
学习了。。
cattycat 2010-06-22
  • 打赏
  • 举报
回复
问题就是这样,不要返回句柄变量的引用。
liutengfeigo 2010-06-22
  • 打赏
  • 举报
回复
我也不清楚为什么那么多人推荐看 c++ Primer,如果没有很好的基础支持,只能说用那些库是自挖坟墓。除了能够让你的思维偷懒,令你的程序变得糟糕,我想不到它有什么好处。


说得很,新手最好别去看。。当字典用才好
MichaelBomb 2010-06-22
  • 打赏
  • 举报
回复
又学习了
走好每一步 2010-06-22
  • 打赏
  • 举报
回复
楼主去看看退栈的实现。系统的栈不是销毁的,楼主好好去看看汇编吧,不要在那臆测,书上的说法并不一定能准确地令你理解。

你的9还在,只是凑巧没有新函数压栈将它覆盖罢了。不要研究这些东西,好好看看汇编,然后学会看vc的反汇编。

引用也不是什么别名,只不过是指针罢了,方便书写而已。更深入点就是32位的无符号数。句柄也只不过是指向结构体的32位指针。

我也不清楚为什么那么多人推荐看 c++ Primer,如果没有很好的基础支持,只能说用那些库是自挖坟墓。除了能够让你的思维偷懒,令你的程序变得糟糕,我想不到它有什么好处。
newholyrock 2010-06-22
  • 打赏
  • 举报
回复
学到了,谢谢
chaiyanlin 2010-06-22
  • 打赏
  • 举报
回复
lz你断点测试一下看看就知道了
尽管m是局部变量,生命期也是只到很熟结束,但你测试以后会看到fp的地址是和m的第一完全一样的!
说白了就像楼上说的,房间没有那么快清理,一般来说我们尽量避免着样的情况不过你说返回引用到也无伤大雅,编译器会警告你。。。。
但如果你返回一个临时指针那就非常危险了
ZangXT 2010-06-22
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 brookmill 的回复:]
引用铁路桥以前的一段精彩回复:

你退房以后,可能半小时后才有人去整理房间,你扔在那里里的卫生纸也许还在那里(变量值没“抹掉”)。也可能你前脚出门,后脚就有人进去打扫了,那你留着里面的痕迹就立即被清掉了。
不过无论里面的痕迹有没有被抹点,你再进入那个房间就是非法行为(你的printf),因为那个房间已经不属于你了,这是小偷行为,被抓住要罚钱的……
[/Quote]
形象,生动,赞。
brookmill 2010-06-22
  • 打赏
  • 举报
回复
引用铁路桥以前的一段精彩回复:

你退房以后,可能半小时后才有人去整理房间,你扔在那里里的卫生纸也许还在那里(变量值没“抹掉”)。也可能你前脚出门,后脚就有人进去打扫了,那你留着里面的痕迹就立即被清掉了。
不过无论里面的痕迹有没有被抹点,你再进入那个房间就是非法行为(你的printf),因为那个房间已经不属于你了,这是小偷行为,被抓住要罚钱的……
chaoliu1024 2010-06-22
  • 打赏
  • 举报
回复
下载地址:Effective C++
brookmill 2010-06-22
  • 打赏
  • 举报
回复
[Quote=引用楼主 zhuanmentiwen 的回复:]
在好多地方都看到,要避免返回局部变量的引用,因为函数执行完毕后,局部变量将会被销毁,返回引用比较危险。
[/Quote]
函数返回之后,m所在的内存就有可能给其他函数使用,他的值就不可靠了。
象楼主给的那段代码,m所在的内存刚好没有别人用过,所以值还没变。
chaoliu1024 2010-06-22
  • 打赏
  • 举报
回复
《Effective C++》这本书介绍的引用不错
stardust20 2010-06-22
  • 打赏
  • 举报
回复
这边的将销毁。。但什么时候销毁不一定。。你输出9是正好在销毁前你访问了这个内存。。要是销毁后就会出错了
ZangXT 2010-06-22
  • 打赏
  • 举报
回复 1
这种假设基于栈空间没有破坏的情形。
看这个:

test.cpp:6: warning: reference to local variable `m' returned
#include<iostream>
using namespace std;

int& func()
{
int m=9;
return m;
}
int& test()
{
int m = 8;
return m;
}
int main()
{
int& fp=func();
test();
cout<<fp<<endl;
return 0;
}

chaoliu1024 2010-06-22
  • 打赏
  • 举报
回复
下面是我自己总结的!每本书介绍C++引用都只有一节

引用引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。
C++包含一个与指针有关的特性,称为“引用”。实际上,引用是一个隐含的指针。使用引用的方式有三种:作为函数参数,作为函数的返回值,或作为单个引用。

一、引用参数
默认时,C++使用按值调用,但是它提供了两种方法来得到按引用调用的参数传递。
首先,可以显式地把一个指针传递给变元。第二,可以使用引用参数。创建一个引用参数,在参数的名字前加上&即可。从技术上讲,i是一个隐含的指针。通常,当把一个值赋给一个引用时,实际上是把改值赋给引用所指的变量。

二、向对象传递引用
当对象作为变元传递给函数是,就创建了该对象的一个副本。当函数结束时,要调用副本的析构函数。然而,通过引用传递时,不创建对象的副本。意味着当函数结束时,没有作为参数的对象被撤销,也不调用参数的析构函数。
通过引用传递最小的对象以外的所有对象要比按值传递它们要快。变元通常传递到堆栈上。因此,要把大对象推进堆栈或从堆栈中弹出,需要花费相当多的CPU周期。
C/C++的函数参数是传值的,如果有大对象(例如一个大的结构)需要作为参数传递的时候,以前的(C语言中)方案往往是指针,因为这样可以避免将整个对象全部压栈,可以提高程序的效率。但是现在(C++中)又增加了一种同样有效率的选择,就是引用。

三、返回引用
函数可以返回引用
char &replace(int i){ return s[i];}
引用作为返回值的时候,有一些规则必须遵守。这些规则包括:
  不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了“无所指”的引用,程序会进入未知状态。
  不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
  可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。


四、独立引用
当创建独立引用时,创建的只是对象的另一个名字,相当于别名(绰号)。所有的独立引用必须在创建时初始化。除初始化以外,用户不能改变引用变量所指的对象。
zhuanmentiwen 2010-06-22
  • 打赏
  • 举报
回复
我用VC6.0也测试了下,返回局部变量的指针,仍然是输出9.
看来我对局部变量的声明周期等理解还有误吧,请大家指出。
brookmill 2010-06-22
  • 打赏
  • 举报
回复
楼主把这段代码运行一下看看
#include<iostream>
using namespace std;

int* func()
{
int m=9;
return &m;
}

void func2()
{
int i=1;
cout << "f2: " << i << endl;
}

int main()
{
int *fp=func();

func2();
cout<<*fp<<endl;

return 0;
}
zhuanmentiwen 2010-06-22
  • 打赏
  • 举报
回复
忘了说一下,我用的编译器是MinGW,貌似这个编译器对标准C++支持比较好吧。

64,636

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧