函数返回引用

时间:2022-09-30 15:28:45
 学习函数模版时,有如下代码。
#include <iostream>
#include <string>
using namespace std;
template <class T>
const T& max(const T& x,const T&y)//个人觉得返回的引用没什么作用!!!
{
return x < y ? y : x;
}
void main()
{
int i1 = 3;
int i2 = 7;
cout << "Maxium is: " <<max(i1,i2)  << endl;

float f1 = 22.5;
float f2 = 12.3;
cout << "Muxium is: " << max(f1,f2) << endl;

string s1 = "test1";
string s2 = "test2";
cout << "Maxium is: " << max(s1,s2) << endl;
}
我的问题
1)T& max这个函数个人觉得因为参数已经是引用了,所以这个函数用的就是实参,所以再返回一个引用,感觉没什么作用,也就是直接T max(const T& x,const T&y),也可以,不知道对不对?
2)string s1 = "test1";
string s2 = "test2";
这两个参数是如何比较大小的?

19 个解决方案

#1


你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

#2


template<>
string & max (const string & x,const string & y)
{
   if(strcmp(x.c_str() , y.c_str())>0 )  
       return x;
   else
       return y;
}

#3


如果需要用到返回值的时候还是有区别的,从第一个字符开始比较AscII值,如果相等继续下一个,否则不执行下一个字符比较,直接返回。

#4


引用 1 楼  的回复:
你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

令:传入引用是为了减少临时变量的长生
这个是的。
我想问的是我既然传了引用,那么我不返回引用也可以,是吗?
非要返回是你说的仅仅为了符合规范吗?

#5


3.比较大小:字典序,和strcmp一样

#6


引用 1 楼  的回复:
你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

仅仅是为了符合规范吗?

#7


引用 3 楼  的回复:
如果需要用到返回值的时候还是有区别的,从第一个字符开始比较AscII值,如果相等继续下一个,否则不执行下一个字符比较,直接返回。

能具体说说“如果需要用到返回值的时候还是有区别的”吗?

#8


引用 6 楼  的回复:
引用 1 楼  的回复:
你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

仅仅是为了符合规范吗?


防止不必要的拷贝而已。保证返回的是传入参数之一,而不是他们的拷贝。其实本来就应该尽量用引用的...

#9


问题1. 理论上来说是可以的。楼主不妨做一个实验,将返回类型改为T,同时给T增加一个析构函数,在该析构函数中增加一个输出语句,比如cout << "destructor" << endl;,看看destructor是否会被输出;再将返回类型改为T&,在看看destructor是否会被输出。

请楼主参考下面的代码(为了代码方便起见,去掉了相关的const,和讨论楼主的问题没有直接关系):

#include <iostream>
#include <string>
using namespace std;

template <typename T>
T MAX(T& x, T& y)//个人觉得返回的引用没什么作用!!!
{
return x < y ? y : x;
}

class A
{
private:
int a;
public:
A(int a):a(a)
{
};

bool operator < (const A& t)
{
if(a - t.a < 0) return 1;
else return 0;
}

friend ostream& operator << (ostream&, const A&);

~A()
{
cout << "destructor" << endl;
}
};

ostream& operator << (ostream& os, const A& c)
{
os << c.a;
    return os;
}

void main()
{
int i1 = 3;
int i2 = 7;
cout << "Maxium is: " << MAX<int>(i1, i2) << endl;

float f1 = 22.5;
float f2 = 12.3;
cout << "Muxium is: " << MAX<float>(f1, f2) << endl;

string s1 = "test21";
string s2 = "test2";
cout << "Maxium is: " << MAX<string>(s1, s2) << endl;

A a1(30);
A a2(20);
cout << "Maxium is: " << MAX<A>(a1, a2) << endl;
cout << "=====================" << endl;
}

如果MAX(T& x, T& y)返回的是T而不是T&,那么在"====================="之上会有一个destructor输出,如果是引用则没有destructor输出。这说明用引用可以提高效率,减少一次临时对象的产生("============="之上的那个destructor输出,正是为了销毁临时对象,之后输出的destructor是程序结束时,要销毁a1和a2所输出的),所以从这点来看,使用引用作为返回值类型至少是可以提高效率的,尤其在A这个类如果很大的时候,提升的效率将更加明显。

当然是用引用作为返回值还有一些别的用途,比如返回值可以作为左值,就像上面代码中的ostream& operator << (ostream& os, const A& c),返回值类型必须是引用ostream&,而不能是ostream,否则无法实现cout << avalue << bvalue << endl;这样的链式操作了。当然这种情况和楼主的问题没有直接的关系,知道就行了。


问题2. 字符串一般是用strcmp函数来比较的。估计string类中提供了操作符<的重载,在重载函数中应该使用了strcmp或者类似功能的函数。

#10


C++Primer第四版有如下的话:P215
返回非引用类型:函数的返回值用于初始化在调用函数处创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样 的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。且其返回值既可以是局部对象,也可以是求解表达式的结果。
这里“临时对象”是什么?是不是形参被分配内存后的东东?怎么会"将函数返回值复制给临时对象"?
谢谢指教

#11


只是为了防止临时变量,如果返回值不是相当底层或者是大的结构体之类的化,除了规范并没有其他用途。如果你不用&引用,其会产生一个临时变量用来存储值,而你用的值就是临时变量的值,

#12


而当使用&后其会根据代码找到你所引用的是什么值,而引用就是相当于变量本身,也就是你传入的&a , 或 &b , 所引用的变量值,编译期也就没有必要再创建临时变量了,这就是差别

#13


2)string s1 = "test1";
string s2 = "test2";
这两个参数是如何比较大小的?

由于string类已经重载了>、<、=号,所以可以直接比较大小。
其实重载函数里也是先用c_str()这个函数来把string对象转换成
C字符串再比较的吧

#14


引用 10 楼  的回复:
C++Primer第四版有如下的话:P215
返回非引用类型:函数的返回值用于初始化在调用函数处创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样 的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。且其返回值既可以是局部对象,也可以是求解表达式的结果。
这里“临时对象”是什么?是不是形参被分配内存后的东东?怎么会"将函数返回值复制给临时对象"?
……



这么说吧,只要返回的不是引用类型,就都会将返回值赋给一个临时对象,临时对象再赋给外部变量,然后临时对象被销毁。如果返回的是引用,就不存在产生临时对象的问题,从而可以省去构造临时对象,析构临时对象所带来的时间和空间方面的开销。

#15


引用 12 楼  的回复:
而当使用&amp;后其会根据代码找到你所引用的是什么值,而引用就是相当于变量本身,也就是你传入的&amp;a , 或 &amp;b , 所引用的变量值,编译期也就没有必要再创建临时变量了,这就是差别

哦,我知道我哪里没搞明白了。
我以前一直以为,只要我函数的形式参数传了引用,如本问题max(const T&x,const T&y)//那么不管函数返回不返回引用,都不会有临时对象的产生。因为我传的就是我的实参。感情我的理解是错的啊?
按14楼的讲法,只要“只要返回的不是引用类型,就都会将返回值赋给一个临时对象,临时对象再赋给外部变量,然后临时对象被销毁”?

#16


引用 14 楼  的回复:
引用 10 楼 的回复:

C++Primer第四版有如下的话:P215
返回非引用类型:函数的返回值用于初始化在调用函数处创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样 的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。且其返回值既可以是局部对象,也可以是求解表达式的结果。
这里“临时对象”是什么?是不是形参被分配内存后的东东?怎么会"将函……

你的意思拿到这个问题来说的话:“只要返回的不是引用类型,就都会将返回值赋给一个临时对象,临时对象再赋给外部变量”返回值赋给临时对象,可是这里的返回值就是我的外部对象啊,比如引用的x,y,再赋给临时对象,然后临时对象又赋给引用的x,y?感觉怎么多此一举呢?

#17


引用 9 楼  的回复:
问题1. 理论上来说是可以的。楼主不妨做一个实验,将返回类型改为T,同时给T增加一个析构函数,在该析构函数中增加一个输出语句,比如cout << "destructor" << endl;,看看destructor是否会被输出;再将返回类型改为T&amp;,在看看destructor是否会被输出。

请楼主参考下面的代码(为了代码方便起见,去掉了相关的const,和讨论楼主的问题没有直接关系……
学习了。

#18


楼主可以去研究一下 effective C++ 这本书的 item2  item19  item22 你的问题就全解开了

#19


引用 18 楼  的回复:
楼主可以去研究一下 effective C++ 这本书的 item2 item19 item22 你的问题就全解开了

谢谢,好好看了下,和C++Primer结合起来,明白了

#1


你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

#2


template<>
string & max (const string & x,const string & y)
{
   if(strcmp(x.c_str() , y.c_str())>0 )  
       return x;
   else
       return y;
}

#3


如果需要用到返回值的时候还是有区别的,从第一个字符开始比较AscII值,如果相等继续下一个,否则不执行下一个字符比较,直接返回。

#4


引用 1 楼  的回复:
你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

令:传入引用是为了减少临时变量的长生
这个是的。
我想问的是我既然传了引用,那么我不返回引用也可以,是吗?
非要返回是你说的仅仅为了符合规范吗?

#5


3.比较大小:字典序,和strcmp一样

#6


引用 1 楼  的回复:
你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

仅仅是为了符合规范吗?

#7


引用 3 楼  的回复:
如果需要用到返回值的时候还是有区别的,从第一个字符开始比较AscII值,如果相等继续下一个,否则不执行下一个字符比较,直接返回。

能具体说说“如果需要用到返回值的时候还是有区别的”吗?

#8


引用 6 楼  的回复:
引用 1 楼  的回复:
你传入的是引用,返回的是引用符合规范,令:传入引用是为了减少临时变量的长生

仅仅是为了符合规范吗?


防止不必要的拷贝而已。保证返回的是传入参数之一,而不是他们的拷贝。其实本来就应该尽量用引用的...

#9


问题1. 理论上来说是可以的。楼主不妨做一个实验,将返回类型改为T,同时给T增加一个析构函数,在该析构函数中增加一个输出语句,比如cout << "destructor" << endl;,看看destructor是否会被输出;再将返回类型改为T&,在看看destructor是否会被输出。

请楼主参考下面的代码(为了代码方便起见,去掉了相关的const,和讨论楼主的问题没有直接关系):

#include <iostream>
#include <string>
using namespace std;

template <typename T>
T MAX(T& x, T& y)//个人觉得返回的引用没什么作用!!!
{
return x < y ? y : x;
}

class A
{
private:
int a;
public:
A(int a):a(a)
{
};

bool operator < (const A& t)
{
if(a - t.a < 0) return 1;
else return 0;
}

friend ostream& operator << (ostream&, const A&);

~A()
{
cout << "destructor" << endl;
}
};

ostream& operator << (ostream& os, const A& c)
{
os << c.a;
    return os;
}

void main()
{
int i1 = 3;
int i2 = 7;
cout << "Maxium is: " << MAX<int>(i1, i2) << endl;

float f1 = 22.5;
float f2 = 12.3;
cout << "Muxium is: " << MAX<float>(f1, f2) << endl;

string s1 = "test21";
string s2 = "test2";
cout << "Maxium is: " << MAX<string>(s1, s2) << endl;

A a1(30);
A a2(20);
cout << "Maxium is: " << MAX<A>(a1, a2) << endl;
cout << "=====================" << endl;
}

如果MAX(T& x, T& y)返回的是T而不是T&,那么在"====================="之上会有一个destructor输出,如果是引用则没有destructor输出。这说明用引用可以提高效率,减少一次临时对象的产生("============="之上的那个destructor输出,正是为了销毁临时对象,之后输出的destructor是程序结束时,要销毁a1和a2所输出的),所以从这点来看,使用引用作为返回值类型至少是可以提高效率的,尤其在A这个类如果很大的时候,提升的效率将更加明显。

当然是用引用作为返回值还有一些别的用途,比如返回值可以作为左值,就像上面代码中的ostream& operator << (ostream& os, const A& c),返回值类型必须是引用ostream&,而不能是ostream,否则无法实现cout << avalue << bvalue << endl;这样的链式操作了。当然这种情况和楼主的问题没有直接的关系,知道就行了。


问题2. 字符串一般是用strcmp函数来比较的。估计string类中提供了操作符<的重载,在重载函数中应该使用了strcmp或者类似功能的函数。

#10


C++Primer第四版有如下的话:P215
返回非引用类型:函数的返回值用于初始化在调用函数处创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样 的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。且其返回值既可以是局部对象,也可以是求解表达式的结果。
这里“临时对象”是什么?是不是形参被分配内存后的东东?怎么会"将函数返回值复制给临时对象"?
谢谢指教

#11


只是为了防止临时变量,如果返回值不是相当底层或者是大的结构体之类的化,除了规范并没有其他用途。如果你不用&引用,其会产生一个临时变量用来存储值,而你用的值就是临时变量的值,

#12


而当使用&后其会根据代码找到你所引用的是什么值,而引用就是相当于变量本身,也就是你传入的&a , 或 &b , 所引用的变量值,编译期也就没有必要再创建临时变量了,这就是差别

#13


2)string s1 = "test1";
string s2 = "test2";
这两个参数是如何比较大小的?

由于string类已经重载了>、<、=号,所以可以直接比较大小。
其实重载函数里也是先用c_str()这个函数来把string对象转换成
C字符串再比较的吧

#14


引用 10 楼  的回复:
C++Primer第四版有如下的话:P215
返回非引用类型:函数的返回值用于初始化在调用函数处创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样 的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。且其返回值既可以是局部对象,也可以是求解表达式的结果。
这里“临时对象”是什么?是不是形参被分配内存后的东东?怎么会"将函数返回值复制给临时对象"?
……



这么说吧,只要返回的不是引用类型,就都会将返回值赋给一个临时对象,临时对象再赋给外部变量,然后临时对象被销毁。如果返回的是引用,就不存在产生临时对象的问题,从而可以省去构造临时对象,析构临时对象所带来的时间和空间方面的开销。

#15


引用 12 楼  的回复:
而当使用&amp;后其会根据代码找到你所引用的是什么值,而引用就是相当于变量本身,也就是你传入的&amp;a , 或 &amp;b , 所引用的变量值,编译期也就没有必要再创建临时变量了,这就是差别

哦,我知道我哪里没搞明白了。
我以前一直以为,只要我函数的形式参数传了引用,如本问题max(const T&x,const T&y)//那么不管函数返回不返回引用,都不会有临时对象的产生。因为我传的就是我的实参。感情我的理解是错的啊?
按14楼的讲法,只要“只要返回的不是引用类型,就都会将返回值赋给一个临时对象,临时对象再赋给外部变量,然后临时对象被销毁”?

#16


引用 14 楼  的回复:
引用 10 楼 的回复:

C++Primer第四版有如下的话:P215
返回非引用类型:函数的返回值用于初始化在调用函数处创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样 的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。且其返回值既可以是局部对象,也可以是求解表达式的结果。
这里“临时对象”是什么?是不是形参被分配内存后的东东?怎么会"将函……

你的意思拿到这个问题来说的话:“只要返回的不是引用类型,就都会将返回值赋给一个临时对象,临时对象再赋给外部变量”返回值赋给临时对象,可是这里的返回值就是我的外部对象啊,比如引用的x,y,再赋给临时对象,然后临时对象又赋给引用的x,y?感觉怎么多此一举呢?

#17


引用 9 楼  的回复:
问题1. 理论上来说是可以的。楼主不妨做一个实验,将返回类型改为T,同时给T增加一个析构函数,在该析构函数中增加一个输出语句,比如cout << "destructor" << endl;,看看destructor是否会被输出;再将返回类型改为T&amp;,在看看destructor是否会被输出。

请楼主参考下面的代码(为了代码方便起见,去掉了相关的const,和讨论楼主的问题没有直接关系……
学习了。

#18


楼主可以去研究一下 effective C++ 这本书的 item2  item19  item22 你的问题就全解开了

#19


引用 18 楼  的回复:
楼主可以去研究一下 effective C++ 这本书的 item2 item19 item22 你的问题就全解开了

谢谢,好好看了下,和C++Primer结合起来,明白了