在一个函数的内部, 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;
}