在leet code上做题遇到了一个坑,算法总认为自己写得没有问题,处理流程造就烂熟于心,用X code调试发现还是疏忽了:C++返回引用和返回对象的差别,在一个函数结束的地方返回了一个临时对象的引用!
根据以往的经验,引用是C++程序中高效能的法宝,节省了对象复制拷贝时的开销,但是滥用引用也会导致意想不到的错误。例如以下的代码:
// 从一个字符串中,从后向前查找一个单词 // @s 源字符串// @index : 查找字符串起始位置的脚标// 返回查找得到的单词,没有找到单词时返回一个含有空字符串的string对象string findBackWord(string &s,int &index) { int endPoint = index; int startPoint = index; int length = 0; int isFirst = 1; int i = 0; string temp(""); for( i = index ; i >= 0;i-- ) { if(isFirst && s.at(i) == ‘ ‘) { continue; } if(isFirst && s.at(i) != ‘ ‘) { endPoint = i ; isFirst = 0; } if(!isFirst && s.at(i) == ‘ ‘) { break; } startPoint = i ; length++; } index = i ; if(length) { temp = s.substr(startPoint,length); } return temp; }
如果函数的返回类型是引用,则该函数返回的对象始终是一个含有空字符串的string对象!何也?返回的是一个临时对象的引用,在函数返回时,临时对象已经释放,教训啊!
一般来说,返回引用时必须保证在调用函数前,被引用的对象已经存在,也就是说要杜绝返回函数中产生的临时对象的引用。那么问题来了,哪些情况需要返回引用,哪些情况又需要返回对象呢?
如果对象的创建、析构的成本代价很大时,需要考虑采用引用的形式,此时返回值一般是作为函数的输出参数。例如:
void add(string a,string b,string &c) { c = a + b; }
这只是一个非常简单的例子,目的是说明引用的适用范围。还有一种情况是引用作为返回的类型,常见与一个类的成员函数返回this指针指向的对象引用,代码如下:
A& A::operator =(const A& x)
{
// do somethin
return *this;
}
三、引用总结
(1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如意的问题。
(2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。
(3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
(4)使用引用的时机。流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。