讨论:C++中函数不能返回局部变量的引用,你是怎么理解的?

一蜉蝣 2012-07-29 11:57:46
C++ Primer中 214页中说千万不要返回局部变量的引用,然后有下面的示例:
const string &mainp(const string &s)
{
string ret=s;
return ret
}
//这个函数在运行的时候会出错,因为它返回了局部变量的引用。
我有点不明白 return ret 分明是返回的局部变量嘛 怎么会是返回局部变量的引用呢?

书上说不能返回局部变量的应用是因为函数在执行完后,系统就释放了局部变量的存储空间。有一点不太明白:函数执行完不就是执行完return语句才叫做执行完吗?那么执行return语句的时候函数还没有执行完。那么局部变量也就没有被释放 那应该还是可以引用的吧。

要是我哪里理解错了的话,请看下面的例子:

#include<iostream>
using namespace std;
int &ref()
{
int ivar=1100; //局部变量
int &irvar=ivar;
return irvar; // 返回了局部变量的引用
}
int main(int argc,char *argv[])
{
cout<<ref();
}

我编译后是可以正确运行的。
请大家解惑:
...全文
1811 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
int8 2014-05-15
  • 打赏
  • 举报
回复
函数返回时的过程是这样的: 函数计算完毕,执行到return语句时,会在内存中自动定义一个临时变量以return的值初始化,之后函数执行完毕,局部变量释放,注意此时临时变量还存在!然后用户根据需要访问或者不访问临时变量,等到执行下一条语句,临时变量自动销毁。 所以不能返回局部变量的引用,因为临时变量指向的内存已经释放! 以下是例证: vs2010

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout<<"无参构造函数"<<endl;
	}
	A(const A& a)
	{
		cout<<"拷贝构造函数"<<endl;
	}
	A& operator = (const A& a)
	{
		cout<<"赋值运算符重载"<<endl;
		return *this;
	}
	~A()
	{
		cout<<"析构函数"<<endl;
	}
private:

};
const A boo(const A a)
{
	cout<<"A tmp = a"<<endl;
	A tmp = a;//调用拷贝构造函数
	cout<<"return tmp"<<endl;
	return tmp;//外部会自动定义一个临时变量,以tmp初始化,所以调用拷贝构造函数
}
int main(int argc,char* argv[])
{
	cout<<"A a"<<endl;
	A a;//调用无参构造函数
	cout<<"A b(a)"<<endl;
	A b(a);//调用拷贝构造函数
	cout<<"-----------------------------------------------"<<endl;
	b=boo(a);//当把a值传递给形参时,会调用拷贝构造函数;返回时,会定义临时变量以函数内返回值初始化
	system("pause");
	return 0;
}
执行结果: A a 无参构造函数 A b(a) 拷贝构造函数 ----------------------------------------------- 拷贝构造函数 A tmp = a 拷贝构造函数 return tmp 拷贝构造函数 析构函数 析构函数 赋值运算符重载 析构函数 请按任意键继续. . .
过野秋风 2013-12-14
  • 打赏
  • 举报
回复
引用 15 楼 yifuyou 的回复:
[Quote=引用 12 楼 的回复:] 刚才我说的话是从书上搬来的。我用vs2010的编译器试了一下,发现确实能通过。 好吧,我现在也不会了。 [/Quote] 我现在好想明白点了:C++ Primer上说的是不能返回局部变量的引用。我觉得这一点说的不太确切。应该改为:不能返回局部变量的引用给一个引用变量。但是如果返回引用给一个相关的非引用变量的话是可以的。下面的例子可以说明这一点。 #include<iostream> using namespace std; int &ref() { int ivar=1100; //局部变量 int &irvar=ivar; return irvar; // 返回了局部变量的引用 } void test() { int a=b=c=d=e=f=g=h=0; } int main() { /*这里函数ref返回局部变量的引用,返回后立即把ivar的值重新赋给了变量i,在主函数中i//是有效的,所以能够得到正确的结果*/ int i=ref(); int &j=ref(); //而下面这句,函数ref返回一个引用给引用变量。所以j就是ivar的别名 test(); //此处调用函数test,则会覆盖已经被系统释放的ivar所占的内存空间。 // 如果注释掉这句会发现下面输出j仍然会得到正确的结果 cout<<i<<endl<<j<<endl; } 我是在vc6.0中运行的 没注释掉test的时候 输出j得到的是一个很大的随机值 注释掉test后仍然能够得到1100;所以我觉得书上的那句话有必要改一改:可以返回局部变量的引用,但是千万不要反回局部变量的引用给一个引用变量。
解释的很正确,但是C++primer上的那句话是没错的,确实不能返回局部变量的引用,你的这种不报错的情况只适用于int,double等值类型的,如果你让他返回一个list,vector等这种类型的运行时候是直接会报错的,例如: #include<iostream> #include<list> using namespace std; list<int>& reset() { int j=10; list<int> newlist; while(j>0) { newlist.push_back(j); j--; } return newlist; } int main() { list<int> mylist; //list<int>& mylist; //这个也是一样报错 mylist=reset(); for(list<int>::iterator iter=mylist.begin();iter!=mylist.end();iter++) { cout<<*iter<<endl; } system("pause"); return 0; } 这个程序跑起来就会报内存错误,因为无论是赋给引用的或者非引用的变量,在调用函数返回后,newlist的值都被list的析构函数中的clear()清除了,即newlist的指向都是未知的,所以报内存错误!在VS2010中亲测。 大部分类都会定义这样的析构函数来释放类中的定义的指针,所以C++Primer中说的也没错,因为它主要考虑的是面向对象程序设计的情况,不过那些值类型的确实有些例外。
neulin 2013-01-28
  • 打赏
  • 举报
回复
引用 15 楼 yifuyou 的回复:
引用 12 楼 的回复:刚才我说的话是从书上搬来的。我用vs2010的编译器试了一下,发现确实能通过。 好吧,我现在也不会了。 我现在好想明白点了:C++ Primer上说的是不能返回局部变量的引用。我觉得这一点说的不太确切。应该改为:不能返回局部变量的引用给一个引用变量。但是如果返回引用给一个相关的非引用变量的话是可以的。下面的例子可以说明这一点。 #i……
我是一个新手,你说的这个我没看明白,只是觉得局部变量没有被立刻销毁,用int i=ref()的时候,值已经被存起来了,而test()的时候,我想是将没用的局部变量的内存覆写了,所以也能理解int& j的结果吧,希望高手指点那。
jianghua327710 2012-10-25
  • 打赏
  • 举报
回复
如果是引用类型的话,返回的是地址,主函数根据地址获取值,如果是局部变量的话,虽然获取到地址,但此时该地址的内容被释放了,如果是局部变量就可以了
一蜉蝣 2012-07-30
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]
因为局部变量或者局部指针所指的内容(在函数内部,用静态方式分配的内存)在函数返回后,就失效了。

以局部指针为例,局部指针本身是能够正常的返回给调用者的,但是局部指针所指向的内容在函数返回后就没有意义了,也就是说调用所得到的指针,它所指向的内容是没有意义的东西。

可以参考:
关于函数返回值的几种情况
[/Quote]

太谢谢你了 豁然开朗
一蜉蝣 2012-07-30
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]
刚才我说的话是从书上搬来的。我用vs2010的编译器试了一下,发现确实能通过。
好吧,我现在也不会了。
[/Quote]

我现在好想明白点了:C++ Primer上说的是不能返回局部变量的引用。我觉得这一点说的不太确切。应该改为:不能返回局部变量的引用给一个引用变量。但是如果返回引用给一个相关的非引用变量的话是可以的。下面的例子可以说明这一点。

#include<iostream>
using namespace std;
int &ref()
{
int ivar=1100; //局部变量
int &irvar=ivar;
return irvar; // 返回了局部变量的引用
}

void test()
{
int a=b=c=d=e=f=g=h=0;
}

int main()
{
/*这里函数ref返回局部变量的引用,返回后立即把ivar的值重新赋给了变量i,在主函数中i//是有效的,所以能够得到正确的结果*/
int i=ref();
int &j=ref(); //而下面这句,函数ref返回一个引用给引用变量。所以j就是ivar的别名
test(); //此处调用函数test,则会覆盖已经被系统释放的ivar所占的内存空间。
// 如果注释掉这句会发现下面输出j仍然会得到正确的结果
cout<<i<<endl<<j<<endl;
}

我是在vc6.0中运行的 没注释掉test的时候 输出j得到的是一个很大的随机值 注释掉test后仍然能够得到1100;所以我觉得书上的那句话有必要改一改:可以返回局部变量的引用,但是千万不要反回局部变量的引用给一个引用变量。

一蜉蝣 2012-07-30
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]
因为局部变量或者局部指针所指的内容(在函数内部,用静态方式分配的内存)在函数返回后,就失效了。

以局部指针为例,局部指针本身是能够正常的返回给调用者的,但是局部指针所指向的内容在函数返回后就没有意义了,也就是说调用所得到的指针,它所指向的内容是没有意义的东西。

可以参考:
关于函数返回值的几种情况
[/Quote]

但是为什么我的例子运行出来是正确的呢?
iamnobody 2012-07-29
  • 打赏
  • 举报
回复
换个说法就是,
当返回值是引用类型时,该引用返回值不能绑定到局部对象.
一蜉蝣 2012-07-29
  • 打赏
  • 举报
回复
谁来解答一下啊
一蜉蝣 2012-07-29
  • 打赏
  • 举报
回复
例子敲错了:返回语句少敲了一个分号:return ret;
nimingzhe2008 2012-07-29
  • 打赏
  • 举报
回复 1
Google了一下英文网站,有人对此的解释是“操作系统还没有立刻将本地变量的内存分配给其他变量,但这是暂时的、不稳定的。”
nimingzhe2008 2012-07-29
  • 打赏
  • 举报
回复
刚才我说的话是从书上搬来的。我用vs2010的编译器试了一下,发现确实能通过。
好吧,我现在也不会了。
nimingzhe2008 2012-07-29
  • 打赏
  • 举报
回复
位于一对{}中的语句叫做block,而在block中声明的变量叫做本地变量,它只在{}中有效。
引用的背后是通过指针实现的。若函数返回本地变量的引用,即代码背后返回一个指针,该指针指向一个已经失效的变量。显然这是错误的
幸运的是,编译器会对这种代码报错。
sliven_ji 2012-07-29
  • 打赏
  • 举报
回复
引用是指一个变量的别名,其本质上其实也是指针,只是不能改变其指向的地址而已。局部变量在退出函数时会释放内存,生命周期结束。而返回的引用实质是返回局部变量的地址。此时该地址下的内存空间已不再属于原来的局部变量了。有可能已分配给别的变量,因此再通过引用来操作该内存空间是不对的。
zhs077 2012-07-29
  • 打赏
  • 举报
回复
局部变量生命周期,当返回后会自动销毁,而返回引用的话,会使用一个已经销毁的对象,这样是不行的
baixiaojin89 2012-07-29
  • 打赏
  • 举报
回复
楼主C++基础不行啊,const string & mainp()返回引用不是看return返回什么而是看函数的返回类型,这明显是引用嘛!
函数在return执行时是没有完,但你要知道引用传递是传递地址,返回也是返回地址,你是把地址给了人家,函数调用结束后地址上的内容就销毁了,所以你指向的内容有可能不存在,或者被别人用了,这样是不可以的。楼主没有明白引用的本质。
pathuang68 2012-07-29
  • 打赏
  • 举报
回复
因为局部变量或者局部指针所指的内容(在函数内部,用静态方式分配的内存)在函数返回后,就失效了。

以局部指针为例,局部指针本身是能够正常的返回给调用者的,但是局部指针所指向的内容在函数返回后就没有意义了,也就是说调用所得到的指针,它所指向的内容是没有意义的东西。

可以参考:
关于函数返回值的几种情况
sadgod 2012-07-29
  • 打赏
  • 举报
回复
局部变量存放在栈上,函数返回后,这段空间被复用了,存在这里是不靠谱的。
hen_hao_ji 2012-07-29
  • 打赏
  • 举报
回复
chanhit 2012-07-29
  • 打赏
  • 举报
回复
所谓引用可以认为是变量的别名,局部变量在函数退出后就销毁了,即便return的时候有效,但是一出来,调用者得到的就是一个无效的东东了,另外楼主的例子用自定义类型试一下就知道了

65,187

社区成员

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

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