您的位置:首页 > 其它

关于函数返回值的几种情况

2012-03-31 21:16 288 查看
转自:http://patmusing.blog.163.com/blog/static/13583496020113191407531/

在一个函数的内部,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是有效的。
再加一点:

char *returnStr()
{
char *p="hello world!";
return p;
}


按照这个逻辑来讲的话,虽然p也是定义在栈区,但是返回的也是复制_p,只不过“hello wolrd”是字符串常量,存放在静态文本区。所以可以理解为return _p; 而_p的值为"hello wolrd"的首地址。

再加一点:

char *returnStr2()
{
char p[] = "hello,world!";
return p;
}


对比两段程序,是不是觉得没什么区别?其实区别大了,第一段程序是定义了一个指针,指向静态区字符常量。而这一段程序确实定义了一个数组,也就是在栈区分配了一段内存,但是在这里却不是将数组的首地址指向"hello,world",而是用“hello,world”来填充这段栈内存。所以返回p的时候,实际上也是返回_p,在return语句执行完毕之后,_p的值实际上是一段已经被释放的栈内存的地址,其内容是不确定的了。

4. 如果不是基本数据类型,比如:

class A
{
public:
OtherClass * ...

};

如果在某个函数内部有一个A类的局部变量,比如:
A a;
return a;
这时候也会返回a的一个拷贝,如果A没有写深拷贝构造函数,就会调用缺省的拷贝构造函数(浅拷贝),这样做就会失败的;
如果A中提供了深拷贝构造函数,则这样做就是可以的。

实验代码如下:

#include<iostream>
usingnamespace
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 =newint(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: