一:先来讲讲什么是临时对象。
临时对象(临时变量):代码中看不见,隐藏在后台,因此我们无法在程序代码中看见临时对象。
临时对象的产生条件有两个: 1.为使函数调用成功而进行隐式类型转换时用到。 2.函数返回值的时候用到
1.为使函数调用成功时
void conv(string str){ ... }
int main(){
conv("abcd");
}
//这种情况下,abcd并不是直接传给str,而是先传递给临时对象,再由临时对象传递给形参str,因为他们俩的类型不一样,(对,你没有看错,这俩类型就是不一样,一个const类型,一个非const类型,所以需要隐式类型转换),看下面的图。
这仅仅是一个参数,所以复制临时对象占用的内存基本可以忽略,但是我们想一想,实际编程中怎么可能只有一组数据,必定是有大量的数据来调用同一个函数的,这样每一个数据我都复制一个临时对象,那么这样占用的内存是非常大的,所以我们要避免让其产生临时对象的这种写法。结合我们之前学的引用传递&,我们发现,引用传递是不需要进行临时对象复制的,因此省下了好多内存。但是问题结束了吗?
答案是不可能的,好了,那么问题又来了,众所周知引用传递是不需要产生临时对象的,我直接就把实参传给str,这样一来就有个小问题,abcd这个字符串常量是const类型,但是str是非const类型,把一个const类型赋给一个非const类型是不允许的。
因此 下面这种使用引用的写法会报错。
#include<iostream>
#include<string>
using namespace std;
void conv(string &str){ //会报错
cout<<"1"<<endl;
}
int main(){
conv("abcd");
}
那有没有什么解决办法呢?
答案是有的:就是加一个const,把非const类型的形参str变成const类型。
写法一:
#include<iostream>
#include<string>
using namespace std;
void conv(const string &str){ //这样就不会报错 ,但是str不能再被修改了。
cout<<"1"<<endl;
}
int main(){
conv("abcd");
}
写法二:重要知识点,非const类型的引用时参数只能时相同类型,而const类型可以实现传递于此类型相关的参数进来。
#include<iostream>
#include<string>
using namespace std;
void conv(string &str){ //这样就不会报错
cout<<"1"<<endl;
}
int main(){
string str="abcd";
conv(str); 这样也可以,
}
2.函数返回值的时候会产生临时对象(不使用引用&的前提,使用引用或者指针会在下面介绍):
void get(){
.....
}
接下来细讲函数返回值的其他两种方式(不产生临时对象):一是指针,二是引用 。
1.先讲讲指针返回(局部变量不能被返回,but why?)
例1:把调用的函数直接设置为指针类型
int *get10(){
int a=10;
int *b=&a;
return b;
}
int main(){
int *c=get10();
cout<<*c<<endl;
}
//我们实际运行一下,会发现可以运行,这个时候我们会有疑问,那这样不是和我前面那个不能返回局部变量的结论冲突了吗?
//其实是因为c++的内存清理机制是惰性的,它并不会在此函数调用完立即清除其占用的内存,而是会在下一个函数进来之后才把上一个函数的内存释放掉。
所以就有了这个程序可以正常运行的现象,但是我们一定得避免这样,养成一个良好的习惯素养。
例二:
#include<iostream>
#include<string>
using namespace std;
int *get10(){
int a=10;
int *b=&a;
return b;
}
int *get20(){
int a=20;
int *b=&a;
return b;
}
int main(){
int *c10=get10();
int *c20=get10();
cout<<"get10的值,应该为10"<<*c10<<endl;
cout<<"get20的值,应该为20"<<*c20<<endl;
}
//这时就出现错误了。
问题的解决办法:作为全局变量,直接把地址传入被调函数。
例:
void add_x_to_Array(int array[],int x){
array[i]=array[i]+x;
}
int main(){
int array[1]={100};
add_x_to_Array(array,10);//直接将地址传入,让调用的函数直接根据指针去原数据快中去修改数据。
2.再讲讲引用返回(直接返回对象本身,不去再复制临时对象)
通过使用引用来替代指针,会使 C++ 程序更容易阅读和维护。C++ 函数可以返回一个引用,方式与返回一个指针类似。
当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。例如,请看下面这个简单的程序:
#include <iostream>
using namespace std;
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};//全局变量
const double& setValues( int i ) //在函数名前加个引用号&即可,写法类似与指针,但是指针那种得在主函数中将承接返回值的变量设置为指针类型。
{//加上const后,函数的返回值在主函数中就不能被随意修改。
return vals[i]; // 返回第 i 个元素的引用
}
// 要调用上面定义函数的主函数
int main ()
{
cout << "改变前的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
setValues(1) = 20.23; // 改变第 2 个元素
setValues(3) = 70.8; // 改变第 4 个元素
cout << "改变后的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;//完成了对全局变量的修改
}
return 0;
}
**总结:我们必须理解底层的机理,可以有利于提高程序的运行效率,让代码变得更加健壮,
临时对象的一开一销很浪费内存,所以我们要尽可能的去除。**