返回引用的函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了返回引用的函数相关的知识,希望对你有一定的参考价值。

#include<iostream.h>int &fun(int &i);int main() int a; cout<<fun(a)<<endl; return 0;int &fun(int &i) i=2; return i;函数fun前有&,若不加也能运行正确,这和加了&的fun函数有啥区别?老师说返回的值是个变量,是这样吗?请详细解释下,谢谢。

楼上几位说的基本详细了,就是返回引用的意思,指返回值是一个引用。你老师说错了。
所谓返回引用是指返回一个已存在对象的引用,(切记一定要是已经存在的)
所谓引用其实就是包装指针的一个语法糖,
所谓语法糖就是说使用引用的地方用指针也可以实现,只不过要写更多的代码。

教科书上对引用这种数据类型讲得很简单,用它给变量起“别名”的作用甚至让人觉得它是多余的!
其实它真正的用武之地是在参数传递中!
众所周知在C语言中不论是从实参到形参,还是从局部变量到返回值,都是清一色的值传递。
值传递意味着全拷贝,不仅效率低下,更多的时候它也并非是你想要的语义。
试想你要去月球,现在从你身上取一个细胞克隆出一个与你同样的人,让它去完成你的探月计划,
然后回来给你讲它的所感所受,或许你能听得身临其境,并且它的成功证明换成你也行,但这是你想要的吗?

T fun(T t)return t; void main() T t; t=fun(t);
在上面的代码中你能发现几个变量?
1.主函数main()中定义了局部变量t
2.调用fun()函数时,自动产生一个局部变量(也就是形参表中的变量t)用于接受实参的值
3.函数fun()返回它自己的形参变量t时,又自动了产生一个匿名临时变量用于存放返回值

T& fun(T& t)return t; void main() T t; t=fun(t);
与上面的代码相比较,不存在第2个和第3个变量。

使用引用常见有以下几种情形:(很不全面,抛砖引玉)
情形一:返回函数实参 T& fun(T& t)return t;
情形二:返回静态变量 T& fun()static T t; return t;
情形三:返回当前对象 T& T::fun()return *this;
情形四:返回新建对象 T& fun()return *new T;
注意与最后一种情形类似但不等价的指针形式如下:
T& fun()T* pt=new T(); return *pt; //除非显式调用delete,否则对象(*pt)不会被释放!
参考技术A 返回引用就说返回这个变量本身,它可以做左值

int &fun(int &i);int main() int a; cout<<fun(a)<<endl;fun(a)=10;////////这个
cout<<a<<endl; return 0;int &fun(int &i) i=2; return i;
参考技术B C++之中函数的返回分为以下几种情况:
1)返回非引用类型:函数的返回值用于初始化在跳出函数时候创建的临时对象。用函数返回值来初始化临时对象与用实参初始化形参的方法是一样的。如果返回类型不是引用的话,在函数返回的地方,会将返回值复制给临时对象。且其返回值既可以是局部对象,也可以是表达式的结果。
2)返回引用:当函数返回引用类型的时候,没有复制返回值,而是返回对象的引用(即对象本身)。
函数返回引用:实际上是一个变量的内存地址,既然是内存地址的话,那么肯定可以读写该地址所对应的内存区域的值,即就是“左值”,可以出现在赋值语句的左边。
《@》函数返回引用的时候,可以利用全局变量(作为函数返回),或者在函数的形参表中有引用或者指针(作为函数返回),这两者有一个共同点,就是返回执行完毕以后,变量依然存在,那么返回的引用才有意义。
小结:
(1)使用引用当作函数参数和返回值,效率更高。
(2)函数返回的对象引用,必须在调用函数前就已经存在,不允许返回局部变量的引用!
(3)当不希望返回的对象被修改的时候,可以添加const。
参考技术C 函数的返回值,大体可以分为3种:返回非引用,返回引用,返回引用左值1、返回非引用
string make_plural(size_t i,const string &word,const string &ending)

return (i==1)?word:word+ending;


以上函数,当i等于1时,函数返回word形参的副本;当i不等于1时函数返回一个临时的string对象,这个临时对象是由字符串word和ending相加而成的。这两种情况下,return都在调用该函数的地方防复制了返回的string对象。
2、返回引用

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

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


以上函数的返回值是引用类型。无论返回s1或是s2,调用函数和返回结果时,都没有复制这些string对象。
注意:不要返回局部对象的引用
const string &mainip(const string &s)

string ret=s;
return ret;


当函数执行完毕,程序将释放分配给局部对象的存储空间。此时,对局部对象的引用就会指向不确定的内存。(我在dev c++里运行通过。。。。 但是vc6和vc2008不能编译通过)。同理,也不能返回局部对象的指针。
3、返回引用左值

char &get_val(string &str,string::size_type ix)

return str[ix];


使用语句调用:
string s("123456");
cout<<s<<endl;
get_val(s,0)='a';
cout<<s<<endl;
把函数应用于左值。

c++ 函数返回引用问题

源码如下:是在VS6上编译的。
#include <iostream>
using namespace std;

//int b=40; //当b为int和static int,f()=10后返回值不同
int &f()

int b=40;
return b;

//所谓返回引用是指返回一个已存在对象的引用,一定是已经存在的。返回值是一个引用。
int main()

int &e=f(); //此处是函数的执行,而非引用的引用。e是f()的别名,跟随f()变动
int e2=f(); //e2是引用函数的返回值,是一个引用。
cout<<"e's address = "<<&e<<"e's value="<<e<<endl;
cout<<"e2's address = "<<&e2<<"e2's value="<<e2<<endl;
cout<<"f()'s address = "<<&f()<<"f()'s value="<<f()<<endl;
f()=10;//此处是引用的指修改,即int b=5; int &a=b; a=6,此时a=6,b=6
cout<<"e's address = "<<&e<<"e's value="<<e<<endl;
cout<<"e2's address = "<<&e2<<"e2's value="<<e2<<endl;
cout<<"f()'s address = "<<&f()<<"f()'s value="<<f()<<endl;
return 0;


//b为auto类型,单步执行都是40,一次执行e第二次值为10,其余40
//b为static类型,单步执行为40,40,40,10,40,10,一次执行也是这样。

1、有人说引用绑定栈内存,引用绑定栈内存是什么意思?
2、为什么b为auto类型时,e单步执行和一次性执行结果不一样啊。主要是不明白怎么就产生这些值了。
3、为什么b为static类型时,e和f()的值为10,又是怎么回事,4、f()=10,这个到底是说函数的引用返回的值是10,或者就是简单赋值,赋值给谁呢?
还是说的什么呢,请多指教一下。非常感谢。

首先,永远不要返回局部变量的引用。因为局部变量在函数返回时被回收,即这个变量不存在了,所以以后对这个变量的引用都是无意义的,结果是不可预知的,程序很可能会崩溃。因此,也就不解释这种情形的结果了。

由于静态变量的声明周期直到程序结束,所以返回静态变量的引用是有意义的,而且安全的。下面解释返回静态变量的引用的情形:

#include <iostream>
using namespace std;

int& f()
    static int b = 40;
    return b;


int main()
    int& e = f();// e为b的别名
    int e2 = f();// e2为b的拷贝

    cout << "e's address = " << &e << "e's value=" << e << endl;
    cout << "e2's address = " << &e2 << "e2's value=" << e2 << endl;
    cout << "f()'s address = " << &f() << "f()'s value=" << f() << endl;
    // 因为e为b的别名,第一个和第三个输出一样

    f() = 10;// 修改b的值

    cout << "e's address = " << &e << "e's value=" << e << endl;
    cout << "e2's address = " << &e2 << "e2's value=" << e2 << endl;
    cout << "f()'s address = " << &f() << "f()'s value=" << f() << endl;
    // 因为e2为b的拷贝,不受影响

    return 0;

追问

请问f()=10为什么是修改b的值,f()我是把他理解为函数的返回值即return b语句吗?修改f()=10,等价于b=10吗?

追答

对的。

假设ff为f()的返回值,则ff的类型为int&,且ff = b,所以ff是b的别名。因为ff为f的返回值,所以f() = 10等价于ff = 10,故f() = 10等价于b = 10。

参考技术A

    指的是你返回一个指向局部变量的引用,包括参数。

    b是int类型,auto在c++中是一个废弃的关键字,不过在c++11中被重新启用,用来自动推导类型。e是一个引用类型,即可以想象成就是被引用的对象,所以当你取e的地址时,其实获得的是被引用的对象地址。由于你的e引用的是一个局部变量,也就是栈上的变量,因为栈的起始地址一般都会随机变化,所以你会得到不一样的结果。随机变化的原因是为了防止某些类型的攻击,提高程序安全性。

    c++中不存在static类型一说,static是用来指示变量的生命周期类型,即静态生命周期。我想你是想说b是static int。当为static int时,程序启动时就会将b初始化为40,此时一直持续到程序结束,所以此时返回引用是合法,因为编译器保证,该变量生命周期会持续整个程序运行期间。

e2 = f();

这里返回引用,而e2不是引用,所以会进行拷贝初始化,所以e2和f()返回的引用是两个对象。e2为40。

f()=10;

这里由于返回引用,而引用指向static int b,所以会对b进行修改,于是b变为10。


e2是main的局部变量,e是引用,f()返回值是引用,此时e等价于f()。当取地址时,e2的地址将不会等于e的地址,因为他们是两个对象,两个对象的地址必然不同(除了一个类的子对象)。这里e2是局部变量,所以分配在栈上,而e,f()指向的是静态变量,所以分配在全局内存中。

追问

非常感谢你的回答,但只能采纳一个,楼上那位写个程序让我看明白了,因此采纳他的答案了,但你所补充的写的很好,非常感谢你。

追答

你可以顶一下你觉得有用的回答。

参考技术B

    引用是绑定内存,意思是一个引用会锁定程序的地址空间中某一地址,地址是常量,只有该地址对应的内存单元的内容可以变化

    这个问题上,先说明一个原则:函数不要返回一个临时变量的引用。因为临时变量在栈区,函数结束时它的地址空间要回收再用,所以接下来这个地址的内容变成不可控。对于auto b的情况,就触犯了这个原则,没有研究的意义。至于为什么单步执行和一次执行结果不一样,可能是VC在不同的调试模式下对地址空间的使用不一样吧。

    b为static的时候,b处于程序的数据段,不在是栈区,因为b不是临时变量了,所以对b进行赋值后,它的状态会保留至函数结束。

    f()=10是赋值,b是auto时,赋值给栈内存;b是static时,赋值给数据段内存。

追问

非常感谢您的回答,言简意赅,切中要害,再加上你所说的和上面回答的,我总是弄明白了,但只能采纳一个答案,就给第一个了,但是非常感谢你。

以上是关于返回引用的函数的主要内容,如果未能解决你的问题,请参考以下文章

C++ 函数返回引用

c++中为啥要函数返回引用?

返回引用到底什么意思????

返回对象和返回引用

返回引用的函数

为什么赋值操作符函数的参数为const引用,返回值为引用