c++返回函数局部对象的引用

    函数千万不要返回局部对象的引用或指针

局部变量在函数里面,当函数执行结束后将释放局部变量,如果返回引用或批针这个时候引用或指针指向所指向的内存空间已经释放。指针和引用将是垂悬指针。很危险!

但是如果返回的“局部变量”是堆中的内存值就可以返回了

C++函数为什么要使用引用?

C语言之中大量利用指针作为形参或者函数返回值,这是由于值拷贝会有很大的消耗(比如传入传出一个大的结构体)。所以在C++之中使用引用作为函数参数和返回值的目的和使用指针是一样的。而且形式上更加直观,所以C++提倡使用引用。

1)返回非引用类型:函数的返回值用于初始化在跳出函数时候创建的临时对象。用函数返回值来初始化临时对象与用实参初始化形参的方法是一样的。如果返回类型不是引用的话,在函数返回的地方,会将返回值复制给临时对象。且其返回值既可以是局部对象,也可以是表达式的结果。

2)返回引用:当函数返回引用类型的时候,没有复制返回值,而是返回对象的引用(即对象本身)。

函数返回引用:实际上是一个变量的内存地址,既然是内存地址的话,那么肯定可以读写该地址所对应的内存区域的值,即就是“左值”,可以出现在赋值语句的左边。

3) 函数返回引用的时候,可以利用全局变量(作为函数返回),或者在函数的形参表中有引用或者指针(作为函数返回),这两者有一个共同点,就是返回执行完毕以后,变量依然存在,那么返回的引用才有意义。

1、引用其实本质就是地址

2、当函数返回值类型为引用时,一般就用引用类型去接收,或者就使用了引用的作用,如果用非引用类型接受,就等于将函数返回的引用的数据值,复制给了该接收对象,和函数返回非引用类型是一样的效果。

3、当函数返回值类型为引用时,如果不考虑接收问题,则有一个特性,则是可以直接操作该函数返回的引用,如放在=左面 +=等.

小结:

(1)使用引用当作函数参数和返回值,效率更高。

(2)函数返回的对象引用,必须在调用函数前就已经存在,不允许返回局部变量的引用!

(3)当不希望返回的对象被修改的时候,可以添加const。

  1. class Node
  2. {
  3. public:
  4. double a;
  5. int b;
  6. char c;
  7. Node(double a=0,int b=0,char c=0)
  8. {
  9. this->a=a;
  10. this->b=b;
  11. this->c=c;
  12. }
  13. //拷贝构造函数
  14. //Node(const Node &n)
  15. //{
  16. //  a=n.a;
  17. //  b=n.b;
  18. //  c=n.c;
  19. //}
  20. };
  21. Node& GetNode()
  22. {
  23. Node str(10.0,2,‘c‘);
  24. return str;
  25. }
  26. int main()
  27. {
  28. Node newnode=GetNode();
  29. cout<<newnode.a<<" "<<newnode.b<<" "<<newnode.c<<endl;
  30. return 0;
  31. }

在上面的代码中,最后能够输出正确的值,然而在函数GetNode()中,str是一个局部的对象,内存空间在栈上,当函数退出时,str的内存空间被回收,这是在高级语言的层面上讲的。但是为什么最后的结果是正确的?原因就是Node newnode=GetNode();这句调用的是默认的拷贝构造函数,如果是自己重新重写拷贝构造函数,而不用默认的拷贝构造函数,那么这段代码就绝对有问题,最后输出的是未定义的数。

然而,为什么用默认的拷贝构造函数就能够正确的输出最后的值呢?

通过调用这段代码的反汇编我们可以看到:

Node newnode=GetNode();

013215FE  call        GetNode (1321019h)

01321603  mov         ecx,dword ptr [eax]               //eax调用GetNode 函数返回的栈的栈顶指针

01321605  mov         dword ptr [newnode],ecx

01321608  mov         edx,dword ptr [eax+4]

0132160B  mov         dword ptr [ebp-10h],edx //这句为double的a数据成员赋值

0132160E  mov         ecx,dword ptr [eax+8]

01321611  mov         dword ptr [ebp-0Ch],ecx  //这句为int的b数据成员赋值

01321614  mov         edx,dword ptr [eax+0Ch]

01321617  mov         dword ptr [ebp-8],edx  //这句为char的c数据成员赋值

cout<<newnode.a<<" "<<newnode.b<<" "<<newnode.c<<endl;

也就是说直接调用默认的拷贝构造函数(或者默认的赋值函数),函数返回,在函数中的局部变量的销毁,其实在栈中只是栈顶的指针的移动,仍然还是可以为其赋值的。

然而:

Node &newnode=GetNode();

cout<<newnode.a<<" "<<newnode.b<<" "<<newnode.c<<endl;//能够输出正确的值

cout<<newnode.a<<" "<<newnode.b<<" "<<newnode.c<<endl;//不能输出正确的值

cout<<&newnode<<endl;

对于代码,newnode是对GetNode函数的引用,当函数结束时,其实是已经吧局部对象str销毁了,但是由于输出的结果仍然还在堆栈中,所以第一个能够输出正确的值,第二个是由于堆栈已经被其他的数覆盖,所以不能输出正确的值,而且这个对象也不能为其赋值,因为它的内存空间已经不存在了。


时间: 2024-10-12 16:19:29

c++返回函数局部对象的引用的相关文章

函数可以返回一个局部对象,而不能返回一个局部对象的引用(指针):

函数可以返回一个局部对象,而不能返回一个局部对象的引用(指针):当函数返回一个局部对象时,虽然这个对象已经释放,但是返回时会产生一个临时的对象.而当返回一个局部对象的引用时,这个对象已经不存在了.这就要求在函数参数中,包含一个引用或指针.int &func(int a,int b,int &retsult){ retsult = a + b; return &retsult}但是如下代码是错误的(返回局部对象的引用)int &func(int a,int b){ int &

函数绝对的不要返回指向局部对象指针或引用,该返回对象就返回对象。

首先我们来看一个例子: #include <iostream> using namespace std; const int &fun1(int a,int b) { int i=0; i = a + b; return i; } int main() { if (fun1(1, 2) == fun1(2, 5)) { cout << fun1(1, 2) << endl; cout << fun1(2, 5) << endl; cout

基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------&gt; 可以返回派生类对象的引用或指针

您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. 百度和网页 http://bbs.csdn.net/topics/380238133 的作者无关,不对其内容负责.百度快照谨为网络故障时之索引,不代表被搜索网站的即时页面. 首页 精选版块 移动开发 iOS Android Qt WP 云计算 IaaS Pass/SaaS 分布式计算/Hadoop J

指向对象的引用置空---与内存泄漏

import java.util.Arrays; public class Stack { private static final int INIT_SIZE = 10; private Object[] datas; private int size; public Stack() { super(); datas = new Object[INIT_SIZE]; } public void push(Object data){ if (size == datas.length) { ext

c/c++不能返回局部对象和局部变量的指针或引用解释

在编写c/c++代码时,调用函数的书写让程序变得整洁易读,但是调用函数的返回值(局部变量的返回值,变量,结构体,数组等)也有注意事项.c/c++严禁返回局部变量的指针或引用. 其实函数的返回值的规则非常好记: 函数的返回值可以是数值和全局变量的指针或引用. 函数的返回值不能是局部对象或者是局部变量的指针或引用!!! 原因: 调用函数的局部变量是存在于栈中的,在执行完调用函数之后会将局部变量的空间释放,也就是调用函数执行后局部变量将不存在与内存中.如果返回的是局部变量的指针或者是引用.返回给接收对

7.4——函数声明,局部对象,内联函数

函数声明: (1)函数在调用之前必须先声明,一个函数可以被声明多次,而只能被调用一次. (2)函数返回值,函数名,函数形参这三个组成函数原型,函数原型描述了函数接口. (3)在头文件中提供函数声明,而在定义函数的的源文件需要包含这个头文件. 局部对象: (1)函数定义的形参和变量的名字只位于函数的作用域中,这些名字只在函数体中可见. (2)自动对象包括函数形参和局部变量,生命周期只存在于函数的执行期间. 静态局部对象(static) (1)若是一个对象位于函数的作用域内,但生命周期存在于函数的多

php的引用&amp;(就是在变量或者函数、对象等前面加上&amp;符号)

官方文档: 1.引用是什么:http://www.php.net/manual/zh/language.references.whatare.php 2.引用做什么:http://www.php.net/manual/zh/language.references.whatdo.php3.引用传递:http://www.php.net/manual/zh/language.references.pass.php4.引用返回:http://www.php.net/manual/zh/language

不能返回函数内部new分配的内存的引用

以前在开发电子秤接口动态库时,曾尝试在用于获取重量的函数外面定义一个字符串指针,然后作为参数传入函数内部,然后在函数内部new,用来输出函数执行过程中发生的错误.但是总是出错,没有找到原因,后来无意中看到了下面的一段说明,忘记摘录出处了,感谢作者. 如下: 不能返回函数内部 new分配的内存的引用(这个要注意啦,很多人没意识到,哈哈... ). 这条可以参照Effective C++[1]的 Item 31.虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部 new分配内存的引用),

js 在嵌套函数中this关键字引用head对象

var myObject = { func1: function() { console.log(this); // myObject var func2 = function() { console.log(this); // window, 从此处开始,this都是window对象了 var func3 = function() { console.log(this); // window, head }(); }(); } } myObject.func1(); var foo = { f