函数值按引用返回常见的一个错误:
先来看一个错误代码:
#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;
}
};
A fun()
{
A *a=new A(3);
return *a;
}
int main()
{
A &b=fun();
cout<<b.GetKey()<<endl;
return 0;
}
该段代码虽然能够正确的输出结果但是却会导致内存泄露。在fun函数中在堆中开辟空间,用指针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 &fun()
{
A *a=new A(3);
return *a;
}
int main()
{
A &b=fun();
cout<<b.GetKey()<<endl;
delete &b;
return 0;
}
但是按引用传递会出现一个问题,就是出现空引用,因为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;
}
};
A *fun()
{
A *a=new A(3);
return a;
}
int main()
{
A *b=fun();
cout<<b->GetKey()<<endl;
delete b;
return 0;
#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;
}