防火、防盗、防拷贝;懂你,懂我,懂临时

本文探讨C++中临时对象的生成与管理,包括函数参数传递方式、类型转换、函数返回对象时的效率问题及如何优化。通过实例分析,揭示了传引用比传值更高效,直接初始化优于拷贝赋值,以及函数返回对象时的优化策略。

防火、防盗、防拷贝;懂你,懂我,懂临时

测试代码:

#include <iostream>
using namespace std;

class testCopy
{
public:
	int i;
	int j;
public:
	testCopy(int m = 0, int n = 0);

	testCopy(const testCopy &ts)
	{
		this->i = ts.i;
		this->j = ts.j;
		cout << "拷贝构造函数被执行!" << endl;
	}

	testCopy & operator=(const testCopy& ts)
	{
		i = ts.i;
		j = ts.j;
		cout << "拷贝赋值运算符执行!" << endl;
		return *this;
	}

	virtual ~testCopy()
	{
		cout << "析构函数被执行!" << endl;
	}

public:
	int Add1(testCopy ts);
	int Add2(testCopy& ts)
};

testCopy::testCopy(int m, int n) : i(m), j(n)
{
	cout << "构造函数被执行!" << endl;
	cout << "i = " << i << endl;
	cout << "j = " << j << endl;
}

int testCopy::Add1(testCopy ts)
{
	int sum = ts.i + ts.i;
	ts.i = 1000;
	return sum;
}
int testCopy::Add2(testCopy& ts)
{
	int sum = ts.i + ts.i;
	ts.i = 1000;
	return sum;
}
一、传值还是传引用

对于上文中的测试代码我们可以发现,两个Add函数的不同在于形参是值或者引用,以下就来测试两种传递方式带来的结果。

int main()
{
	testCopy myobj(10, 20);
	int sum1 = myobj.Add1(myobj);
	cout << "sum1=" << sum1 << endl;
	cout << "myobj.i = " << myobj.i << endl;
	cout << "-----------------------------------------" << endl;
	int sum2 = myobj.Add2(myobj);
	cout << "sum2=" << sum2 << endl;
	cout << "myobj.i = " << myobj.i << endl;
	return 0;
}

在这里插入图片描述

  • return 0;时的析构函数未被呈现!
  • 我们可以很容易的发现,让我们使用传值的方式给函数传递参数时,函数使用传入的myobj拷贝构造了一个临时对象ts,用这个临时进行操作,当然,我们修改i的值,仅仅修改了临时对象ts中的 i 值,并未对myobj造成影响。函数结束后,该临时对象生命周期结束,随之调用析构函数。
  • 提升效率的方法是:使用传引用的方式给函数传递参数。从结果中我们容易发现,并没有拷贝构造函数执行,这是因为我们直接把myobj交给了函数进行操作,这样修改 i 值的时候,myobj的i值被修改为1000 。
二、类型转换生成临时对象
int main()
{
	testCopy myobj2;
	myobj2 = 1000; //构造临时对象

	cout << "=========================================" << endl;
	testCopy myobj3 = 1000;

	getchar();
	return 0;
}

在这里插入图片描述

  • 当我们在执行 myobj2 = 1000; 语句时,系统使用1000构造了一个临时对象,然后在使用拷贝赋值运算符将该临时对象拷贝赋值给 myobj2 。
  • 提升效率的方法是,直接在声明myobj2的时候就传入初值1000,这样系统不会生成临时对象,不会调用拷贝赋值运算符,这个等号的语义是:定义时初始化。
三、隐式类型转换以保证函数调用成功
int calculate(const string& source, char ch)
{
	const char *p = source.c_str();
	int icount = 0;

	return icount;
}
int main()
{
	char mystr[100] = "I Love China,oh,baby!";
	int result = calculate(mystr, 'o');

	getchar();
	return 0;
}

我们发现,传入的实参与函数接收的形参类型并不相同,而编译器没有报错,这之中有什么悬机呢?

  • 原来 int result = calculate(mystr, ‘o’); 这里系统会使用mystr来构造一个string类型的临时变量,再将此临时变量的引用链接上形参source,传入函数。(前提是形参是一个const修饰的常量,如果没有const将失败!)
  • 为什么不加const会失败呢?原因是:不加const时,系统会认为你有修改系统创建的string类型临时变量的倾向,这是万万不被允许的!怎么能修改一个系统产生的临时对象呢?所以c++只会为const引用产生临时变量
  • 我们需要避免这种情况发生,老老实实传入相同类型的变量,不要给系统增加负担!
四、函数返回对象时
testCopy Double1(testCopy& ts)
{
	testCopy temp;
	temp.i = ts.i * 2;
	temp.j = ts.j * 2;

	return temp;
}

int main()
{
    //(1)
	testCopy myobj4(10, 20);
	Double1(myobj);
	cout << "=========================================" << endl;
	//(2)
	testCopy myobj5(10, 20);
	testCopy myobj6 = Double1(myobj);
	

	getchar();
	return 0;
}

在这里插入图片描述

  • return 0;时的析构函数不被呈现!
  • 情况(1)中,返回对象时,系统使用temp拷贝构造了一个临时对象,temp在Double函数结束时,随即被析构,而因为没有使用对象来接收,这个临时对象随即被析构。
  • 情况(2)中,我们创建了对象来myobj6来接收,那么此时系统构造的临时对象不会被立刻析构,而是与myobj6作用域相同。可以认为,这个临时对象使用了myobj6的预留空间,不会自己创建新空间。
  • 接下来我们要提升效率
testCopy Double2(testCopy& ts)
{
	return testCopy(ts.i * 2, ts.j * 2);
}

int main()
{
    //(1)
	testCopy myobj4(10, 20);
	Double2(myobj);
	cout << "=========================================" << endl;
	//(2)
	testCopy myobj5(10, 20);
	testCopy myobj6 = Double2(myobj);
	

	getchar();
	return 0;
}

在这里插入图片描述

  • return 0;时的析构函数不被呈现!
  • 这样效率得到了提升,没有临时对象被构造。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值