面试集锦--函数的按引用返回与按地址返回
函数值按引用返回常见的一个错误:
先来看一个错误代码:
#include<iostream>using namespace std;class A{private:int a;public:A(int num):a(num){cout<<"构造函数!"<<endl;}A(A &b){a=b.a;cout<<"复制构造函数!"<<endl;}~A(){cout<<"析构函数"<<endl;}void Setkey(int num){a=num;}int GetKey(){return this->a;}};//按引用返回,但是a是局部变量,因此超出fun函数作用域之后//a就消失了,所以b是一个不存在的对象的别名,所以程序输出随机数A&fun(){A a(3);return a;}int main(){A &b=fun();cout<<b.GetKey()<<endl;return 0;}该代码输出随机数字,而不是3,原因如代码中注释所说,按引用返回,但是a是局部变量,因此超出fun函数作用域之后a就消失了,所以b是一个不存在的对象的别名,所以程序输出随机数
我们可以做如下修改:去掉A&fun()中的&:
#include<iostream>using namespace std;class A{private:int a;public:A(int num):a(num){cout<<"构造函数!"<<endl;}A(A &b){a=b.a;cout<<"复制构造函数!"<<endl;}~A(){cout<<"析构函数"<<endl;}void Setkey(int num){a=num;}int GetKey(){return this->a;}};//函数按值返回,必定会调用类的复制构造函数构造一个对象a的副本//在main函数中定义一个对象作为副本的别名,而对于引用而言,如//果引用的是一个临时变量,那么这个临时变量的生存期不少于引用的//生存期。也就是说main函数中的副本会在b这个别名生存期结束//之后才消失。A fun(){A a(3);return a;}int main(){A &b=fun();cout<<b.GetKey()<<endl;return 0;}
函数的输出结果是:
构造函数!
复制构造函数!
析构函数
3
析构函数
请按任意键继续. . .
正如代码中的注释所说,
函数按值返回,必定会调用类的复制构造函数构造一个对象a的副本在main函数中定义一个对象作为副本的别名,而对于引用而言,如引用的是一个临时变量,那么这个临时变量的生存期不少于引用的生存期。也就是说main函数中的副本会在b这个别名生存期结束之后才消失。
下面看一个利用按引用返回和按地址返回来解决内存泄露的问题:
#include<iostream>using namespace std;class A{private:int a;public:A(int num):a(num){cout<<"构造函数!"<<endl;}A(A &b){a=b.a;cout<<"复制构造函数!"<<endl;}~A(){cout<<"析构函数"<<endl;}void Setkey(int num){a=num;}int GetKey(){return this->a;}};void fun(A &a){a.Setkey(99);}int main(){A *b=new A(23);fun(*b);cout<<b->GetKey()<<endl;delete b;return 0;}