设置返回一个对象的函数c++_使用C++临时对象的后果

1581bd9329b5e8eb49b1c0efca0ac131.png

结论

这篇文章没什么意思,就是告诉大家一个常识,函数不要返回引用类型的临时对象,也不要引用函数返回的临时对象,因为无法预测会发生什么。

但是!我就是想看看这么做的糟糕后果是什么!

定义

先要搞清楚什么是临时对象,这里我参考 《More Effective C++》99页定义。真正的临时对象是在源码中不可见的,是栈上的、没有名字的对象。与函数内定义的临时对象有根本差别。

有两种情况:

第一种:当触发隐式类型转换时

例如:

// 统计ch在str中出现的次数

此时,char[] 隐式转换为 string,再引用为str。该隐式转换的string,会在counterChar返回时销毁。

第二种:当函数返回一个对象的时候

例如:

const Number operator+(const Number& lhs, const Number& rhs);

在函数返回时,会产生一个临时对象作为返回值(当然编译器会帮你优化它,所以不一定有一个临时对象生成和销毁)。

实验:

对象的类实现为:

class Cat {
	string name;
public:
	Cat(string name): name(name) 
	{
		cout << "new cat " << name << endl;
	}

	Cat(const Cat& cat)
	{
		cout << "copy " << name << endl;
		this->name = cat.name;
	}

	void sleep() const
	{	
		cout << "sleep " << name << endl;
	}

	~Cat() 
	{
		cout << "destroy cat " << name << endl;
	}
};

很简单,为了看清现象打了一些日志。

情况一(正常情况):函数使用值返回,同样拷贝赋值来保存函数返回值。

Cat foo1() 
{
	Cat a("a");
	Cat b("b");
	return b;
}

int main()
{
	Cat c = foo1();
        c.sleep()
        cout << "end mainn"; 
}

下面来观察运行结果:

new cat a

new cat b

copy

destroy cat b

destroy cat a

sleep b

end main

destroy cat b

简单解释一下:foo1运行到return b时,会执行一次拷贝构造函数。此时,main函数的c对象构造完成。之后会将两个局部对象销毁。

情况二:函数返回值为引用型

Cat& foo1() 
{
	Cat a("a");
	Cat b("b");
	return b;
}

在VS的Debug模式中,会先执行函数局部对象的销毁,再返回这个局部对象的引用。之后调用Cat的拷贝构造函数。由于引用的对象已经被销毁。故会报错

再Release模式中,现象很神奇:

new cat a

new cat b

destroy cat b

destroy cat a

copy

sleep

end main

destroy cat

也就是说,对象c为虽然执行了拷贝构造函数,但并没有复制name成员。导致对象c的name未知。

情况三:引用函数的返回对象

Cat foo1() 
{
	Cat a("a");
	Cat b("b");
	return b;
}

int main()
{
	const Cat &c = foo1(); // 由于函数返回值为右值,这里必须是const引用
        c.sleep()
        cout << "end mainn"; 
}

在Debug模式下,现象与情况一相同,变量c引用的是一个匿名对象。

new cat a

new cat b

copy

destroy cat b

destroy cat a

sleep b

end main

destroy cat b

在Release模式下,很有意思

new cat a

new cat b

destroy cat a

sleep b

end main

destroy cat b

由于编译器的优化,foo函数局部变量b真的被main函数局部变量c所引用了,其内存释放也是在main函数返回时完成的。

综上所述

不要试图使用"引用"来减少构造和析构函数的调用。如果你非要优化的话,建议使用返回值优化(RVO)。

Cat foo2()
{
	return Cat("b");
}

如此一来,main函数中的变量c就不会调用拷贝构造了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值