【C++修炼之路 第二章:类和对象】(补充)函数传值返回 和 传引用返回 有什么区别?




在这里插入图片描述



传值返回 和 传引用返回 有什么区别?

传值返回的过程:先 生成一个临时对象,拷贝需要传的那个对象,然后这个临时对象再作为 返回值 返回,因而会调用一次拷贝构造函数


结合例子理解:

看这个函数:


传值返回:返回对象d 的拷贝

class Date{
    //....
}
Date func()
{
	Date d;
	return d;
}
int main()
{
	func();
	return 0;
}

func 函数结束,会析构对象 d,对象d会被销毁,因此需要 一个临时对象返回



说一下返回值接收问题

1、用 Date ref 接收:需要一次拷贝构造,但是这里存在权限放大

int main()
{
	Date ref= func();
	return 0;
}

2、用 const Date ref 接收:因为返回值为 临时对象(具有常性,权限为只读),若用 Date ref 接收,会使其权限放大,因此要 const 修饰,使权限缩小

int main()
{
	const Date ref= func();
	return 0;
}

3、用 Date& ref :上面两种情况都需要一次拷贝构造,这里使用引用直接省去一次拷贝

int main()
{
	Date& ref= func();
	return 0;
}



传引用返回:返回对象d 的别名

Date& func()
{
	Date d;
	return d;
}

结合上面的第三种返回值接收方式:

int main()
{
	Date& ref= func();
	return 0;
}

ref 是临时对象的别名,则 ref 也就是 对象d 的别名



此时注意!!!

       首先,函数 func 结束阶段,会调用 对象d 的析构函数,析构掉 对象 d,数值都被析构成一些其他数值(如你定义的析构数值)

       其次,函数 func 真正结束后, func的函数栈帧销毁,对象d 指向的那块空间也“释放掉”(数值不一定是 你定义的析构数值 了),此时别名 ref 相当于“野指针”了,指向一片“不属于你的空间”(对象别名的底层是指针,返回对象的别名,实际上是返回对象的指针)

       所以,调试可以看到,ref 的日期数值 不是 对象d 的数值,而是一些奇怪的随机数,因为这片空间不是对象d 的,而是系统的了(系统自己会覆盖一下其他数上去)

       另外,你在上面那段代码的基础上多加几个函数(随便定义几个),运行后可以发现,居然 ref 的日期数值又变其他数了
(根源就是 ref 指向的空间已经是系统的了,新定义的函数在同一块栈区开辟函数栈帧,新函数的数值可能会覆盖了这片空间,就可能直接覆盖到 ref所指的那片空间



小结一下上面这段话
       返回对象是一个局部对象或者临时对象,出了当前func函数作用域,就析构销毁了,那么不能用引用返回
       虽然引用返回可以减少一次拷贝,但是用引用返回是存在风险的,因为引用对象在func函数栈帧已经销毁了
如果出了函数作用域,返回对象还在,才能用引用返回



注意其中的本质:存在函数栈帧销毁的风险

那么我们可以 将对象定义成 static ,定义在静态区,则不受栈区的影响

又或者 对象可以是 new 出来的,new在堆区开辟空间



但我们也不能以 是否在栈区来判断
看个反例:*赋值运算符重载的返回值 this 也在栈上,但是这个返回不会出事
解析: * this 是 对象本身,对象在main的作用域里创建,因此出 main作用域才析构销毁而出函数作用域不会销毁,所以 此处能引用返回

从这里又可以理解:只要你定义的对象,不在当前的函数栈帧里面就可以引用返回(这个函数销毁了也不会影响到自己)

// 赋值运算符重载
Date& operator=(const Date& d) {
	if (this != &d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}



记住一个核心:

出了作用域,返回对象还在没有析构,那就可以用引用返回,减少拷贝()
a、返回对象生命周期到了,会析构,传值返回
b、返回对象生命周期没到,不会析构,传引用返回

为什么要减少拷贝?
1、没有拷贝,提高效率
2、多拷贝生成一个对象,就要多用一次析构函数,也是开销

当要拷贝的内容非常多时,通常析构内容也不少,同时往往一个函数不传引用,会影响到很多个对象,性能开销将大大增加
因此,虽然传引用的条件稍微苛刻,但是尽量还是传引用

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值