C++中的返回类型与内存释放

文章讨论了C++中运算符+和*的重载,强调了返回类型对内存管理的影响。返回对象时,系统会调用复制构造函数,而返回对象引用则避免了这一开销,但需要手动管理内存。C++11引入的智能指针可以帮助自动管理内存,避免内存泄漏,同时指出在使用智能指针时,不应返回引用,以防止在返回后对象被析构。
摘要由CSDN通过智能技术生成
  • 原题地址

  • 此题训练点是运算符+*的重载

  • 但我想借用此题浅浅谈一下我对“返回类型”&“内存释放”的理解

  • 首先先贴一个大家可能都会这么写的AC代码

#include <iostream>
using namespace std;

class Complex
{
private:
	int real, image;
public:
	Complex(int real = 0, int image = 0) :real(real), image(image) {}
	~Complex() {}
	Complex operator+ (Complex& obj)
	{
		Complex* ans = new Complex(real + obj.real, image + obj.image);
		return *ans;
	}
	Complex operator* (Complex& obj)
	{
		Complex* ans = new Complex(real * obj.real - image * obj.image,
			real * obj.image + image * obj.real);
		return *ans;
	}
	void Output()
	{
		cout << real << ((image >= 0) ? "+" : "") << image << "i" << endl;
	}
};

int main()
{
	int x, xx, y, yy, z, zz;
	cin >> x >> xx >> y >> yy >> z >> zz;
	
	Complex a(x, xx), b(y, yy), c(z, zz);
   
	Complex res = a + b + c;
	// 等价于 Complex res = a.operator+(b).operator+(c);
    Complex ans = a * b * c;
	// 等价于 Complex ans = a.operator*(b).operator*(c);
    
	res.Output();
	ans.Output();

	return 0;
}
  • 由于上述程序重载+与重载*形式完全一致,故以下仅以重载+为例

    注意观察:函数左上角声明的返回值类型与函数最后一行的return语句

  1. 返回值类型:对象

    return内容:对象

    	Complex operator+ (Complex& obj)
    	{
    		Complex* ans = new Complex(real + obj.real, image + obj.image);
    		return *ans;
    	}
    
  2. 返回值类型:对象的引用

    return内容:对象

    	Complex& operator+ (Complex& obj)
    	{
    		Complex* ans = new Complex(real + obj.real, image + obj.image);
    		return *ans;
    	}
    

可以看到两者的return的内容完全一致,仅仅在左上角声明的返回值类型不同

  1. 对于上述第一种,主函数调用时写成

    Complex res = a + b + c;
    
  2. 对于上述第二种,主函数调用时写成

    Complex& res = a + b + c;
    

可以看到两者的唯一区别也仅仅是一个&运算符

  • 那么区别在哪呢
  1. 第一种写法,不需要手动释放空间,系统会自动执行析构函数,释放掉主函数中的

    Complex a, b, c, res
    

    而第二种写法,系统同样会自动执行析构函数,释放掉主函数中的

    Complex a, b, c
    

    但是主函数中申请出来的res需要手动释放

    delete& res
    
  2. 返回对象会触发复制构造函数,此程序没写,故默认触发;而返回对象引用不会。因此,返回对象引用比返回对象更高效

  3. 对于返回对象,如果这个对象在函数中是以局部变量的形式存在的话(对象的存在形式有两种),

    • 一种就是上面AC代码的写法,自己申请的空间,在堆里;
    • 一种就是直接作为局部变量,在栈里;

    那么,首先这个对象被返回之后,系统将自动销毁这个局部变量,其次被返回的这个对象是左值,即无法改变的常量

    而返回对象的引用,在函数中只能是一种存在形式,即自己申请的空间,同样是在堆里,这个引用的对象被返回后,是右值,即可以修改值

    (其实对于一个已经存在的变量,是一定要的返回对象的引用的,因为后续对这个变量的操作都将改变这个最原始的变量;而如果此时返回对象的话,触发默认复制构造函数不说,此后对这个变量的操作都将失效,会造成严重的内存泄漏(原来那个存在的变量的空间这辈子都释放不了了)与逻辑错误)

    所以

    	Complex operator+ (Complex& obj)
    	{
    		Complex* ans = new Complex(real + obj.real, image + obj.image);
    		return *ans;
    	}
    

    其实是很不规范的写法hhh,应该要返回引用的hhh

    规范化总结3.

    • 对于局部变量,只能返回作为左值的对象,否则如果返回这个局部变量的引用,有两种方法会让程序崩溃

      1. 修改被返回的引用的值(对已经被销毁的东西进行操作显然不行)
      2. delete这个引用的对象的指针(因为已经被销毁了)
    • 对于已经存在的(其实就是堆里的)变量,一定要返回对象的引用

  • 好吧,但是返回对象的引用还需要手动释放空间,好麻烦的,有什么自动帮我实现上述功能的语法吗?没错当然有!在C++11中,引入了智能指针这么一个概念可以自动实现

    • 申请空间
    • 识别到变量全部操作完后…
    • 释放空间
  • 于是上述两个重载函数分别可以写成

    	Complex operator+ (Complex& obj)
    	{
    		unique_ptr<Complex> ans(new Complex(real + obj.real, image + obj.image));
    		return *ans;
    	}
    
    	Complex operator* (Complex& obj)
    	{
    		unique_ptr<Complex> ans(new Complex(real * obj.real - image * obj.image,
    			real * obj.image + image * obj.real));
    		return *ans;
    	}
    
    • 智能指针包含在头文件#include <memory>

    • return语句执行完之后由于申请出的ans被识别出已经没有用了,自动执行析构函数,释放内存,是不是很方便hhh

    • 但是要注意的是,这两个函数一定不能返回引用,因为此处的ans变量相当于局部变量了。因为在执行return语句后,就自动执行析构函数,将这个ans变量释放掉了

    感觉逻辑性好差 😦 希望大家可以读懂并且欢迎指正 Orz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr_Dwj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值