关于函数返回值的几种情况
在一个函数的内部,return的时候返回的都是一个拷贝,不管是变量、对象还是指针都是返回拷贝,但是这个拷贝是浅拷贝。
1. 如果返回一个基本类型的变量,比如:
int a; a = 5; return a
那么就会a的一个拷贝,即5返回,然后a就被销毁了。尽管a被销毁了,但它的副本5还是成功地返回了,所以这样做没有问题。
2. 但是对于非动态分配(new/malloc)得到的指针,像1那么做就会有问题,比如在某个函数内部:
int a[] = {1, 2}; return a;
那么也会返回指针a的一个拷贝,我们假定a的地址值为0x002345FC,那么这个0x2345FC是能够成功返回的。当return执行完成后,a就要被销毁,也就是0x002345FC所指向的内存被回收了,也即失去了对该内存的控制。如果这时候在函数外面,去地址0x002345FC取值,那得到的结果肯定是不对的。这就是为什么不能返回局部指针的原因。返回局部变量的引用的道理和这个类似。
3. 对于返回(动态分配得到的)指针的另外一种情况,比如在函数内部:
int a = new int(5); return a;
这样做是可以的。return a执行完后,a并没有被销毁(必须要用delete才能销毁a),所以这里返回的a是有效的。
4. 如果不是基本数据类型,比如:
class A { public: OtherClass * ... };
如果在某个函数内部有一个A类的局部变量,比如:
A a; return a;
这时候也会返回a的一个拷贝,如果A没有写深拷贝构造函数,就会调用缺省的拷贝构造函数(浅拷贝),这样做就会失败的;
如果A中提供了深拷贝构造函数,则这样做就是可以的。
实验代码如下:
#include <iostream> using namespace std; int some_fun1(){ int a = 5; return a; //OK } int* some_fun2(){ int a = 5; int *b = &a; return b; // not OK } int* some_fun3(){ int *c = new int(5); return c; // OK, return c执行完后,并没被销毁(必须要用delete才能销毁) } class CSomething { public: int a; int b; public: CSomething(int a, int b) { this->a = a; this->b = b; } }; class CA{ private: CSomething* sth; // 以指针形式存在的成员变量 public: CA(CSomething* sth) { this->sth = new CSomething(sth->a, sth->b); } // 如果不实现深拷贝,请注释这个拷贝构造函数 CA(CA& obj) { sth = new CSomething((obj.sth)->a, (obj.sth)->b); } ~CA(){ cout << "In the destructor of class CA..." << endl; if (NULL != sth) delete sth; } void Show() { cout << "(" << sth->a << ", " << sth->b << ")" << endl; } void setValue(int a, int b){ sth->a = a; sth->b = b; } void getSthAddress(){ cout << sth << endl; } }; CA some_fun4(){ CSomething c(1, 2); CA a(&c); return a; // 如果CA没有实现深拷贝,则not OK;如果实现深拷贝,则OK } int main(int argc, char* argv[]){ int a = some_fun1(); cout << a << endl; // OK int *b = some_fun2(); cout << *b << endl; // not OK,即便返回结果正确,也不过是运气好而已 int *c = some_fun3(); // OK, return c执行完后,c并没有被销毁(必须要用delete才能销毁) cout << *c << endl; delete c; CA d = some_fun4(); // 如果CA没有实现深拷贝,则not OK;如果实现深拷贝,则OK d.Show(); return 0; }