函数值按引用返回常见的一个错误:
先来看一个错误代码:
#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; }
按地址传递的方法如下:
#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; }