关于“函数能否返回局部对象或变量的引用和指针”
作为一个初学者,对与C++函数的传参和返回值一直比较头疼,这一点就没有Java简单,Java中只有引用传参,返回值也是引用(Java的返回值是否全是引用或其他也没明白,对于Java而言,对搞明白返回值具体是啥貌似没有意义)。对于C++而言,就要灵活的多,而且也复杂的多。函数的参数有三种传参形式,分别是值传递,引用传递和指针传递,而返回值也有三种,返回引用,指针和值。
看到书上和其他地方说,“函数千万不要返回局部对象或变量的引用和指针”,今天就实地验证了一下。下面这个例子是关于向量加法。前四种方法是将结果也作为参数;后四种方法没有将结果作为参数,而是在函数体内部一定了一个局部变量,然后将此局部变量以引用或者指针的形式作为函数的返回值。这八种方法中有的是以指针为参数,有的是以引用为参数。
有人指出如果函数返回的是局部变量的引用或指针的话,变量所指向的地址在多次运行之后,就会发生改变,所以这里将每种方法的运行结果都运行9次。最后的实测结果是,这八种函数都能顺利通过编译器,而且每一种方法的9次运行结果都是一样的,变量所指向的地址和变量的值都没有改变。
本来这个不是个什么问题,在编写3D数学支持库时,需要用到大量的二元甚至三元变量之间的计算,例如计算向量、矩阵和四元数等相关操作。如果能将计算结果作为返回值返回,而不需要将结果作为函数的参数,这样做,无疑就可以减少一个参数,使得函数看着也清晰易懂。因此就有了“函数返回局部对象或变量的引用和指针的问题”。
各位大大看下是否可以这样做(按照后四种少一个参数的做法)?不吝赐教!
程序代码:
/* * test.cpp * * Created on: 2013-8-16 * Author: xiaohun */ #include <iostream> using namespace std ; class Vector3D { public: float x,y,z; public: Vector3D(){ x=y=z=0; }; Vector3D(float x,float y,float z){ this->x=x;this->y=y;this->z=z; }; void print(char* v); static Vector3D& Add1(Vector3D& v1,Vector3D& v2,Vector3D& v); static Vector3D& Add2(Vector3D* v1,Vector3D* v2,Vector3D* v); static Vector3D* Add3(Vector3D& v1,Vector3D& v2,Vector3D& v); static Vector3D* Add4(Vector3D* v1,Vector3D* v2,Vector3D* v); static Vector3D& Add5(Vector3D& v1,Vector3D& v2); static Vector3D& Add6(Vector3D* v1,Vector3D* v2); static Vector3D* Add7(Vector3D& v1,Vector3D& v2); static Vector3D* Add8(Vector3D* v1,Vector3D* v2); }; /** * 返回输出变量的引用,输入参数和输出参数都为引用 */ Vector3D& Vector3D::Add1(Vector3D& v1,Vector3D& v2,Vector3D& v){ v.x=v1.x+v2.x; v.y=v1.y+v2.y; v.z=v1.z+v2.z; return v; } /** * 返回输出变量的引用,输入参数和输出参数都为指针 */ Vector3D& Vector3D::Add2(Vector3D* v1,Vector3D* v2,Vector3D* v){ v->x=v1->x+v2->x; v->y=v1->y+v2->y; v->z=v1->z+v2->z; return *v; } /** * 返回输出变量的指针,输入参数和输出参数都为引用 */ Vector3D* Vector3D::Add3(Vector3D& v1,Vector3D& v2,Vector3D& v){ v.x=v1.x+v2.x; v.y=v1.y+v2.y; v.z=v1.z+v2.z; return &v; } /** * 返回输出变量的指针,输入参数和输出参数都为指针 */ Vector3D* Vector3D::Add4(Vector3D* v1,Vector3D* v2,Vector3D* v){ v->x=v1->x+v2->x; v->y=v1->y+v2->y; v->z=v1->z+v2->z; return v; } /** * 返回局部变量的引用(局部变量的引用作为输出),输入参数为引用,没有输出参数 */ Vector3D& Vector3D::Add5(Vector3D& v1,Vector3D& v2){ Vector3D* v=new Vector3D(); v->x=v1.x+v2.x; v->y=v1.y+v2.y; v->z=v1.z+v2.z; return *v; } /** * 返回局部变量的引用(局部变量的引用作为输出),输入参数为指针,没有输出参数 */ Vector3D& Vector3D::Add6(Vector3D* v1,Vector3D* v2){ Vector3D* v=new Vector3D(); v->x=v1->x+v2->x; v->y=v1->y+v2->y; v->z=v1->z+v2->z; return *v; } /** * 返回局部变量的指针(局部变量的指针作为输出),输入参数为引用,没有输出参数 */ Vector3D* Vector3D::Add7(Vector3D& v1,Vector3D& v2){ Vector3D* v=new Vector3D(); v->x=v1.x+v2.x; v->y=v1.y+v2.y; v->z=v1.z+v2.z; return v; } /** * 返回局部变量的指针(局部变量的指针作为输出),输入参数为指针,没有输出参数 */ Vector3D* Vector3D::Add8(Vector3D* v1,Vector3D* v2){ Vector3D* v=new Vector3D(); v->x=v1->x+v2->x; v->y=v1->y+v2->y; v->z=v1->z+v2->z; return v; } void Vector3D::print(char* v){ for(int i=0;i<=8;i++){ cout<<"第"<<i+1<<"次v=("<<this->x<<","<<this->y<<","<<this->z<<")"<<this<<endl; } } /** * 返回输出变量的引用,输入参数和输出参数都为引用 */ void func1(){ cout<<"返回输出变量的引用,输入参数和输出参数都为引用"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D v; Vector3D::Add1(v1,v2,v); v.print("v"); } /** * 返回输出变量的引用,输入参数和输出参数都为指针 */ void func2(){ cout<<"返回输出变量的引用,输入参数和输出参数都为指针"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D v; Vector3D::Add2(&v1,&v2,&v); v.print("v"); } /** * 返回输出变量的指针,输入参数和输出参数都为引用 */ void func3(){ cout<<"返回输出变量的指针,输入参数和输出参数都为引用"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D v; Vector3D::Add3(v1,v2,v); v.print("v"); } /** * 返回输出变量的指针,输入参数和输出参数都为指针 */ void func4(){ cout<<"返回输出变量的指针,输入参数和输出参数都为指针"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D v; Vector3D::Add4(&v1,&v2,&v); v.print("v"); } /** * 返回局部变量的引用(局部变量的引用作为输出),输入参数为引用,没有输出参数 */ void func5(){ cout<<"返回局部变量的引用(局部变量的引用作为输出),输入参数为引用,没有输出参数"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D v; v=Vector3D::Add5(v1,v2); v.print("v"); } /** * 返回局部变量的引用(局部变量的引用作为输出),输入参数为指针,没有输出参数 */ void func6(){ cout<<"返回局部变量的引用(局部变量的引用作为输出),输入参数为指针,没有输出参数"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D v; v=Vector3D::Add6(&v1,&v2); v.print("v"); } /** * 返回局部变量的指针(局部变量的指针作为输出),输入参数为引用,没有输出参数 */ void func7(){ cout<<"返回局部变量的指针(局部变量的指针作为输出),输入参数为引用,没有输出参数"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D* v=new Vector3D(); v=Vector3D::Add7(v1,v2); v->print("v"); } /** * 返回局部变量的指针(局部变量的指针作为输出),输入参数为指针,没有输出参数 */ void func8(){ cout<<"返回局部变量的指针(局部变量的指针作为输出),输入参数为指针,没有输出参数"<<endl; Vector3D v1(2,3,4); Vector3D v2(1,2,3); Vector3D* v=new Vector3D(); v=Vector3D::Add8(&v1,&v2); v->print("v"); } int main(){ func1(); func2(); func3(); func4(); func5(); func6(); func7(); func8(); return 0; }
结果如下:
返回输出变量的引用,输入参数和输出参数都为引用
第1次v=(3,5,7)0x22ff20
第2次v=(3,5,7)0x22ff20
第3次v=(3,5,7)0x22ff20
第4次v=(3,5,7)0x22ff20
第5次v=(3,5,7)0x22ff20
第6次v=(3,5,7)0x22ff20
第7次v=(3,5,7)0x22ff20
第8次v=(3,5,7)0x22ff20
第9次v=(3,5,7)0x22ff20
返回输出变量的引用,输入参数和输出参数都为指针
第1次v=(3,5,7)0x22ff20
第2次v=(3,5,7)0x22ff20
第3次v=(3,5,7)0x22ff20
第4次v=(3,5,7)0x22ff20
第5次v=(3,5,7)0x22ff20
第6次v=(3,5,7)0x22ff20
第7次v=(3,5,7)0x22ff20
第8次v=(3,5,7)0x22ff20
第9次v=(3,5,7)0x22ff20
返回输出变量的指针,输入参数和输出参数都为引用
第1次v=(3,5,7)0x22ff20
第2次v=(3,5,7)0x22ff20
第3次v=(3,5,7)0x22ff20
第4次v=(3,5,7)0x22ff20
第5次v=(3,5,7)0x22ff20
第6次v=(3,5,7)0x22ff20
第7次v=(3,5,7)0x22ff20
第8次v=(3,5,7)0x22ff20
第9次v=(3,5,7)0x22ff20
返回输出变量的指针,输入参数和输出参数都为指针
第1次v=(3,5,7)0x22ff20
第2次v=(3,5,7)0x22ff20
第3次v=(3,5,7)0x22ff20
第4次v=(3,5,7)0x22ff20
第5次v=(3,5,7)0x22ff20
第6次v=(3,5,7)0x22ff20
第7次v=(3,5,7)0x22ff20
第8次v=(3,5,7)0x22ff20
第9次v=(3,5,7)0x22ff20
返回局部变量的引用(局部变量的引用作为输出),输入参数为引用,没有输出参数
第1次v=(3,5,7)0x22ff20
第2次v=(3,5,7)0x22ff20
第3次v=(3,5,7)0x22ff20
第4次v=(3,5,7)0x22ff20
第5次v=(3,5,7)0x22ff20
第6次v=(3,5,7)0x22ff20
第7次v=(3,5,7)0x22ff20
第8次v=(3,5,7)0x22ff20
第9次v=(3,5,7)0x22ff20
返回局部变量的引用(局部变量的引用作为输出),输入参数为指针,没有输出参数
第1次v=(3,5,7)0x22ff20
第2次v=(3,5,7)0x22ff20
第3次v=(3,5,7)0x22ff20
第4次v=(3,5,7)0x22ff20
第5次v=(3,5,7)0x22ff20
第6次v=(3,5,7)0x22ff20
第7次v=(3,5,7)0x22ff20
第8次v=(3,5,7)0x22ff20
第9次v=(3,5,7)0x22ff20
返回局部变量的指针(局部变量的指针作为输出),输入参数为引用,没有输出参数
第1次v=(3,5,7)0x3e2cc0
第2次v=(3,5,7)0x3e2cc0
第3次v=(3,5,7)0x3e2cc0
第4次v=(3,5,7)0x3e2cc0
第5次v=(3,5,7)0x3e2cc0
第6次v=(3,5,7)0x3e2cc0
第7次v=(3,5,7)0x3e2cc0
第8次v=(3,5,7)0x3e2cc0
第9次v=(3,5,7)0x3e2cc0
返回局部变量的指针(局部变量的指针作为输出),输入参数为指针,没有输出参数
第1次v=(3,5,7)0x3e2cf0
第2次v=(3,5,7)0x3e2cf0
第3次v=(3,5,7)0x3e2cf0
第4次v=(3,5,7)0x3e2cf0
第5次v=(3,5,7)0x3e2cf0
第6次v=(3,5,7)0x3e2cf0
第7次v=(3,5,7)0x3e2cf0
第8次v=(3,5,7)0x3e2cf0
第9次v=(3,5,7)0x3e2cf0