开发者

C++中的函数返回值与拷贝用法

开发者 https://www.devze.com 2022-12-03 11:26 出处:网络 作者: 白给程序猿
目录C++函数返回值与拷贝如果我们返回值为Man&会有什么区别变化呢?这里我解释一下返回值不是引用的情况时整个函数执行的过程总结C++函数返回值与拷贝
目录
  • C++函数返回值与拷贝
  • 如果我们返回值为Man&会有什么区别变化呢?
    • 这里我解释一下返回值不是引用的情况时整个函数执行的过程
  • 总结

    C++函数返回值与拷贝

    js

    先来谈谈对C++中函数返回return的理解,自己本来在学Java,但是平时学校的项目是用的C++,所以在平时搬砖时经常会有一些问题,今天就来谈谈前段时间注意到的一个很小的知识点,话不多说,先上列子。

    首先我们创建一个简单的Man类,实现它的无参构造函数、有参构造函数和析构函数:

    class Man
    {
    public:
    	Man() {
    		cout << "构造" << endl;
    		data = new int(0); }
    
    	Man(const Man& m)
    	{
    		cout << "拷贝构造" << endl;
    		this->data = m.data;
    	}
    	
    	~Man() 
    	{ 
    		cout << "析构" << endl;
    		delete data; 
    	}
    	
    	int* data;
    };
    

    声明一个get函数获取一个Man的对象

    Man get(Man& m)
    {
    	cout << "----" << endl;
    	return m;
    }

    main函数中执行下列代码

     void main()
    {
    		Man javascriptm, n;
    		//cout << "before m=" << &m << "n=" << &n << endl;
    		*m.data = 5;
    		printf("m.data is %d\n", *m.data);
    		n = get(m); 
    
    		printf("m.data is %d\n", *m.data);
    		printf("n.data is %d\n", *n.data);
    	
    	    system("pause");
    	    }
    

    你可以试着想一想三个printf的输出结果分别是多少

    执行结果如下图所示:

    C++中的函数返回值与拷贝用法

    在输出结果里我们可以清楚的看到,Man m, n; 创建了m,n两个对象,调用了构造函数,对m对象中的data赋值,然后我们调用get(Man& man) 函数,注意这里函数参数是引用类型,因此传入的对象是m对象本身,这里我们要区别get(Man man) 两种函数参数类型的区别,我稍后再提。get(Man& man) 函数调用完毕后,返回对象m。

    按照我们过去的分析会认为对象n等于get函数返回的m对象 (n=m) (注意这里等号=被重载过),m对象中的int* data 成员值直接赋值给了n对编程象中的data成员,输出时照理说m和n的data值都应该等于5的,但是:

    为什么这里输出结果却表明这个data指针指向的空间被销毁了?

    为什么get函数执行里会多出了拷贝构造和析构这两个过程呢?

    如果我们返回值为Man&会有什么区别变化呢?

    这里我们做一个对比,填加一个getR函数,返回值为Man& 引用类型:

    Man& getR(Man& m)
    {
      cout << "----" << endl;
     return m;
    }

    接下来我们调用getR这个函数看一看输出结果:

    void main()
    {
      Man m, n;
      *m.data = 5;
      printf("m.data is %d\n", *m.data);
      n = getR(m);
      
      printf("m.data is %d\n", *m.data);
      printf("n.data is %d\n", *n.data);
      
       system("pause");
       }

    执行结果如下图所示: 

    执行结果如下图所示:

    C++中的函数返回值与拷贝用法

    可以看到,当我们返回的是m对象的的引用时,getR 函数执行时没有调用拷贝构造和析构函数

    这里我解释一下返回值不是引用的情况时整个函数执行的过程

    (个人拙劣的理解)

    我们再回到get这个函数:

    Man get(Man& m)
    {
    	cout << "----" << endl;
    	return m;
    }

    首先函数参数传入m编程客栈这个对象的引用我们毋庸置疑,关键就在return这里。

    我们捋一捋函数从开始到结束这个过程,随着Main函数调用get函数,get函数入栈,同时get方法对应的栈帧(储存函数局部变量、返回地址等信息)也入栈,这里的局部变量也就是m对象的引用。

    当我们return这个m对象时,会在内存中创建一个临时的Man temp对象,同时这个temp对象调用其拷贝构造函数,也就是Ma开发者_JAVA开发n temp(m) 。

    C++中的函数返回值与拷贝用法

    完成temp对象的创建后,get函数出栈,对应的栈区内容被销毁,这时系统会调用m对象的析构函数,注意这里有一个陷阱!!!!

    由于m对象是在main方法下的栈区创建的,因此get方法出栈后,系统调用m析构函数并没有真正把m对象在栈区销毁(因为它根本就不是在get方法的栈区上),调用析构函数仅仅php是将data指针所指向的内存空间被销毁了(delete data;),这也解释了为什么m.data的值为-572662307。

    main方法执行完毕后,m对象才会调用析构函数真正被销毁,当然,这也会带来另一个问题,data指向的内存区被执行了两次delete,运行结束后你也就会发现还会有一个**“析构”**和一个内存问题报错。

    C++中的函数返回值与拷贝用法

    回到我们返回的值上:

    n = get(m); 

    这里实际上可以理解成

    Man temp(m);
    n=temp;

    当然由于get函数的退出调用析构函数时,data指针指向的内存区域数据已经被销毁,自然n和m得到的值是一个错误值了。

    总结

    对于函数返回值类型为非引用类型(当然引用类型也可以理解为Man& temp=m),都是会在内存中创建一个临时变量,将返回值拷贝到临时变量中,而返回值是作为函数调用栈区中的局部变量,随着函数的返回,栈区的销毁,而被销毁。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消