C++函数返回引用、非引用以及临时变量的问题

C++中新增了引用类型,所以函数的返回值可以是引用类型。那么就会有人想问 返回引用类型与返回非引用类型有区别吗?

结论是显然的,而且有明显的区别。尤其初学者会很容易绕进去。让我们先看四个函数原型。以int类型来举例

(1) int fun(...)

{

return ....//后面跟的是一个引用

}

例如:int fun(int &a)

{

return a;

}

(2)int fun(...)

{

return....//后面跟的是一个非引用

}

例如:int  fun(int a)

{

return a;

}

(3)int& fun(...)

{

return....//后面跟的是一个引用

}

(4)int& fun(...)

{

return....//后面跟的是一个非引用

}

上面四种函数,(1)(2)是返回非引用类型的函数,(3)(4)是返回引用类型的函数。对于返回的是哪种类型的函数,我们要看函数名前面的参数类型,而不是函数体内return后的类型,这点切记!!!

一、C++规定当函数返回的是非引用类型时,函数会创建临时对象(temporary object),函数返回的就是这个临时对象。在求解表达式时,如果需要一个地方存储其运算结果,编译器会创建一个没有命名的对象,这就是临时对象。浅显的说,当你调用了函数,函数会 return一个值  那么这个值总得有存放的地方吧,编译器就把会把值存放在一个没有命名法临时对象中。

看一个简单的程序

对应于(2)
#include<iostream>
int fun(int &a)
{
int b=a;
return b;
}
int main()
{
 int a=8;
 int b=fun(a);//***
return 0;
}

int b=fun(a);分析此行代码:因为fun是返回非引用函数,调用fun函数,函数体内执行return时,需要创建临时变量temp,相当于执行了 int temp;然后把return的值赋值给temp,相当于执行了temp =b;然后用temp的值初始化b,相当于执行了int b=temp。

int b=fun(a);等加于int temp;temp=b;int b=temp;

当此表达式结束后 temp会消亡,所以不能int& b=fun(a); temp是在fun中的局部变量,fun调用完,表达式结束后,temp消亡,b引用的变量temp不存在了,所以编译不会通过。

对应于(1)

#include<iostream>
int fun(int &a)
{
return a;
}
int main()
{
 int a=8;
 int b=fun(a);//***
return 0;
}

int b=fun(a);分析此行代码:同上,等同于int temp;temp=a//用a引用的变量的值赋值给temp;int b=temp//用temp初始化b,当表达式结束后,temp会消亡。

二、C++规定当函数返回的是引用类型时。C++primer 上说当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。

//find longer of two strings

const string &shorterString(const string &s1,const string &s2)

{

return s1.size()<s2.size()?s1:s2;

}//行参和返回类型都是指向const string对象的引用,调用函数和返回结果时,都没有复制这些string对象。

例如下面函数,请分析:

int a;

int& fun()

{

return a;

}//因为a是全局变量,函数的返回值是a本身,a具有全局作用域。假如a是函数内的局部变量,则函数会出错。

按照C++primer的说法 返回的是a这个全剧变量本身。为了跟返回非引用函数的统一,我本人理解返回的是对全局变量的引用即int b=fun(a);我理解为int &temp=a;int b=temp。可能这样理解有点牵强。函数返回的是引用,引用就是变量的别名,可以等同于初化它的对象,引用=变量(初始化引用的变量),所以函数返回的就算a变量本身。

int a;

int& fun()

{

int &b=a;

return b;

}//a的别名b,但是这个别名只能在fun函数体内使用,出了fun函数体就会消亡,函数返回值是引用,那么返回的其实就是a这个变量!!!

千万不要返回局部对象的引用

int &fun(int &a)

{

int b=a;

return b;

}

此函数运行会出错,因为它返回了局部对象的引用。当函数执行完毕,int b占用的存储空间会被释放,函数返回值指向了对于这个程序来说不再有效的内存空间。

确保返回引用安全的一个好方法是:请自问,这个引用指向哪个在此之前存在的对象?

三、把返回引用以及非引用的函数赋值给其他变量

函数返回值(int Func1())时,要产生一个临时变量作为函数返回值的副本(保存该函数调用中要返回的值),而用引用返回值 (int &Func2())时,不产生值的副本。故在用函数返回值定义一个引用(int &ia = Func1())时,该引用为临 时变量的引用,由于临时变量作用域短暂,故该引用存在随时无效的危险,是不合法的。而用引用返回值时,由于不产生值的副本,故 int &i = func2();在func2()的返回值是一个静态或者全局变量的情况下的调用是合法可行的,其直接用全局数据区中的变量来 初始化引用i,当然如果Func2中的返回值是局部变量,那么当然是非法的。

不妨自己再分析一下下面的四种函数调用:

条件:
int Func1();//假设是合法函数
int &Func2();//假设是合法函数

情况:
int &i = Func2();//引用i引用的是与一个变量,这个变量作用域大于等于int &i,合法
int &ia = Func1();//引用ia引用的是临时变量,不合法
int ib = Func1();//临时变量初始化ib,合法
int ic = Func2();//Func2返回的对象(变量)本身初始化ic;
记得这好像是钱能的那本C++教程里面的题目,应该没有记错。

时间: 2024-10-20 23:11:29

C++函数返回引用、非引用以及临时变量的问题的相关文章

理解-加号重载要使用全局函数+返回值非引用

一.C++中的加号重载使用全局函数的一个有点是可以使用级联的方式进行加法操作. Fraction a,b,c,d,e; A=b+c+d+e; 若为成员函数 1.返回的b的this指针分别作用于后面的变量,因此是对b的修改: 2.如果返回一个新的变量,上面的级联的问题似乎可以解决. 3.问题在于如果存在隐式类型转换,且第一个参数为需要转化的类型时,可能找不到该定义的成员函数,因此使用全局的方式可以便面这个问题 二.返回值需要时一个值,而不是引用 从一个局部函数返回引用,可以考虑两种情况. 1.如果

函数返回值与引用

一段代码 #include <iostream> float temp; ? ? ? ?//全局变量,驻留在内存的data区 float fn1(float r){ ? ?temp = r*r*3.14; ? ?return temp } float&?fn2(float r){ ? ?temp= ?r*r*3.14; ? ?return temp; } int main(){ ???float a=fn1(5.0); //1 ? ?float& b=fn1(5.0); //2

实战c++中的string系列--函数返回局部变量string(引用局部string,局部string的.c_str()函数)

当函数返回字符串的时候,我们可以定义返回string和string&. 1写一个返回string引用的函数 std::string & TestStringReference() { std::string loal_str = "holy shit"; return loal_str; } 这个函数当然是错误的,编译器会提示我们: 返回局部变量或临时变量的地址: loal_str 即不能返回局部变量的引用. 2写一个返回string的函数(函数返回局部变量string

C++11函数返回右值引用

我们定义了一个可以传入右值引用的构造函数的类B,在使用std::move的时候,我们非常容易犯一个错误.看下面的代码: class B { public: B() :s(10), ptr(new int[s]) { std::cout << "default constructor" << std::endl; for (int i = 0; i < s; i++) { ptr[i] = i; } } B(const B& b) :s(b.s) {

C++ Primer 学习笔记_17_从C到C++(3)--引用、const引用、引用传递、引用作为函数返回值、引用与指针区别

欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 一.引用 1.引用是给一个变量起别名 变量: 名称 空间 引用: 引用不是变量 引用仅仅是变量的别名 引用没有自己独立的空间 引用要与它所引用的变量共享空间 对引用所做的改变实际上是对它所引用的变量的改变 引用在定义的时候必须要进行初始化 引用一经初始化,不能重新指向其他变量 2.定义引用的一般格式: (1)类型  &引用名 = 变量名: (2)例如: int a=1; int &b=a; // b是a的别名,因此a和b是同一个单元 (3)

JavaSE8基础 函数返回抽象类的引用,这个引用指向的是子类的对象

os :windows7 x64    jdk:jdk-8u131-windows-x64    ide:Eclipse Oxygen Release (4.7.0)        代码: abstract class Person { public abstract void sayHello(); } class Javaer extends Person{ public void sayHello() { System.out.println("Java Hello"); } }

将引用作为函数返回值的优缺点

格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }好处:在内存中不产生被返回值的副本:(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的.因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!注意事项:(1)不能返回局部变量的引用.这条可以参照Effective C++[1]的Item 31.主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态.(2)不能返回函数内部new

将引用作为函数返回值的格式、好处和规则

格式: 类型标识符 &函数名(形参列表及类型说明){//函数体} 好处: 在内存中不产生返回值的副本(返回一个局部变量的引用是不可取的,因为随着局部变量生存周期的结束,相应的引用也会失效,产生runtime error) 注意: 不能返回局部变量的引用,局部变量会在函数返回后被销毁. 不能返回函数内部new分配的内存的引用,虽然不存在局部变量的被动销毁问题,但是函数返回的引用只是作为一个临时变量出现,并没有被赋予一个实际的变量,导致引用所指向的空间无法释放. 可以返回类成员的引用,但最好是con

C++返回值的引用与非引用

转自: https://blog.csdn.net/qq_22660775/article/details/89854545 返回引用与返回非引用的区别: 返回引用时,函数内部不会构造一个临时变量,而是直接将返回值返回出去.而当为非引用时,会构造一个临时变量(但不一定),然后返回这个匿名的临时变量. 举例: class B { public: B(){ cout << "B的构造函数" << endl; } B(int i){ cout << &qu