C++编程经验:对象优化,试试?试试就逝世哈哈哈

Posted 看,未来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++编程经验:对象优化,试试?试试就逝世哈哈哈相关的知识,希望对你有一定的参考价值。

天天说,new一个对象,但是有想过要如何写出更高效的对象操作代码吗?动手试过吗?

这里是一个用来示例的类,代码很简单,稍微瞟一眼就好:

#include<iostream>

using namespace std;

class test {
public:
	test(int a = 10) :ma(a) { cout << "test()" << endl; }
	~test() { cout << "~test()" << endl; }
	test(const test& t) :ma(t.ma) { cout << "test(const test&)" << endl; }

	test& operator = (const test& t) {
		cout << "operator = " << endl;
		ma = t.ma;
		return *this;
	}

private:
	int ma;
};

案例一:

int main() {
	test t1;
	test t2(t1);
	test t3 = t1;

	//test(20) 显示生成临时对象,生存周期为所在的语句
	test t4 = test(20);

	cout << "***********************************************" << endl;
	return 0;
}

可以自己猜一下打印结果。

test()
test(const test&)
test(const test&)
test()
***********************************************
~test()
~test()
~test()
~test()

由上述结果可以看出:

int main() {
	test t1;				//调用test(int)
	test t2(t1);		//调用test(const test&)
	test t3 = t1;	//调用的依旧是test(const test&)

	//test(20) 显示生成临时对象,生存周期为所在的语句
	test t4 = test(20); //调用的是test(int)
	//这里本应该是先初始化一个临时对象,再讲临时对象拷贝给t4,
	//但事实是直接为t4调用一个构造函数,将20的值传入,这是C++在 构造对象 时的优化
	//这一点可以从最后的四次析构得到应证
	
	cout << "***********************************************" << endl;
	return 0;
}

案例二:
在上面的基础上加上两行:

int main() {
	test t1;
	test t2(t1);
	test t3 = t1;

	//test(20) 显示生成临时对象,生存周期为所在的语句
	test t4 = test(20);

	t4 = t2;				
	t4 = test(30);
	cout << "***********************************************" << endl;
	return 0;
}

可以再想想接下来的结论:

test()
test(const test&)
test(const test&)
test()
operator =
test()
operator =
~test()
***********************************************
~test()
~test()
~test()
~test()
t4 = t2;				// 这里调用了复制构造函数
t4 = test(30);	// 这里产生了临时对象
//与上面的情况有所不同的是,这里是给一个对象进行赋值,而上面是构造
//所以这里先使用构造函数构造了一个临时对象,再使用复制构造函数将临时对象复制到t4
//离开了这条语句之后,临时对象的生命周期结束,调用析构

------------------

operator =
test()
operator =
~test()

案例三:
在上面的基础上再进行添加:

int main() {
	test t1;
	test t2(t1);
	test t3 = t1;

	//test(20) 显示生成临时对象,生存周期为所在的语句
	test t4 = test(20);

	t4 = t2;
	t4 = test(30);

	t4 = (test)30;
	t4 = 40;
	cout << "***********************************************" << endl;
	return 0;
}

现在呢,又会产生什么样的结果嘞?

test()
test(const test&)
test(const test&)
test()
operator =
test()
operator =
~test()
test()
operator =
~test()
test()
operator =
~test()
***********************************************
~test()
~test()
~test()
~test()
t4 = (test)30;		//强制类型转换
//编译器会去查看类有没有对应的构造函数
//如果有,则生成一个临时对象,跟上面那结尾那个一样

t4 = 40;
//这个也几乎一样道理,不过上面的是显示类型转换,下面这个是隐式类型转换

------------------------------

operator =
~test()
test()
operator =
~test()

案例四:
在上面的基础上继续添加:

int main() {
	test t1;
	test t2(t1);
	test t3 = t1;

	//test(20) 显示生成临时对象,生存周期为所在的语句
	test t4 = test(20);

	t4 = t2;
	t4 = test(30);

	t4 = (test)30;
	t4 = 40;
	cout << "***********************************************" << endl;

	//test* p = &test(40);			//&要求一个左值
	const test& pp = test(50);	//非常量引用的对象必须是一个左值

	cout << "***********************************************" << endl;
	
	return 0;
}

好的,引用要求一个左值,让我们再来看一下结果:

***********************************************
test()
***********************************************
~test();

可以看到,引用对象调用了一个临时对象,出了作用域之后并不被析构掉,也即是说可以用。
但是函数结束之后也是要挂掉的。

这里是编译器审查的比较严格。


此外,再讲两个构造的调用时机:
1、全局对象的构造会在函数刚开始运行的时候。
2、静态对象在程序运行的时候会分配空间,但是在函数运行到的时候才会构造。
3、它们都在函数结束的时候析构。


接下来我们看函数调用中的对象优化。


案例五:
在上面的基础上,我们在类外再加这么一个函数:

test* GetObject(test t) {
	int val = t.getdata();
	test temp(val);
	return &temp;
}

这里是不能这么写的,因为 temp(val) 是一个栈内临时对象,在函数结束的时候就会被析构的,如果编译不过就算了,我的VS编译过了,于是卡死了,果然没有让我失望哈。


案例六:
一波微调

test GetObject(test t) {	
//不能返回局部或临时对象的指针或引用
	int val = t.getdata();
	test temp(val);
	return temp;
}

//第一个main,做参照
int main() {
	test t1;
	test t2;
	
	cout << "***********************************************" << endl;

	return 0;
}

//第二次运行的main
int main() {
	test t1;
	test t2;
	t2 = GetObject(t1);
	cout << "***********************************************" << endl;

	return 0;
}

产生结果:

//第一次运行的main
test()
test()
***********************************************
~test()
~test()
//第二次运行的main

test()
test()
test(const test&)
test()
test(const test&)
~test()
~test()
operator =
~test()
***********************************************
~test()
~test()

差距好大。。

记住这里,一会儿要回来

那么,对比一下,结果就是:

t2 = GetObject(t1);

产生:

test(const test&)
test()
test(const test&)
~test()
~test()
operator =
~test()

这之间有什么离奇曲折的故事呢?

首先,t1 作为实参传递给形参,怎么传递的?复制构造函数嘛。

为什么这么说呢,咱凡事讲证据。

void GetObject(test t) {
	int val = t.getdata();
	cout << "***********************************************" << endl;
	/*test temp(val);
	return temp;*/
	//return NULL;
}

int main() {
	test t1;
	test t2;
	GetObject(t1);
	cout << "***********************************************" << endl;

	return 0;
}

我把那底下的都注释了,返回值也免了,于是得出这么一个结果:

test()		//t1
test()		//t2
test(const test&)	//构造形参
***********************************************
~test()		//说明是离开了函数作用域才被析构掉的
***********************************************
~test()
~test()

可以说明这个传参的过程只执行了一次复制构造函数。

那么,对比上面那次,剩下的这段又是怎么肥四呢?:

test()
test(const test&)
~test()
~test()
operator =

再修改,给函数一个返回值看看:

test GetObject(test t) {
	int val = t.getdata();
	cout << "-----------------------------------------------" << endl;
	/*test temp(val);
	return temp;*/
	return NULL;
}

运行结果:

test()
test()
test(const test&)
-----------------------------------------------
test()
~test()
~test()
***********************************************
~test()
~test()

去掉前面的影响,可以看到返回值对函数的影响是:产生了一个构造函数,并产生了一个析构函数。

为了探究这个这个析构函数是在哪里产生的,我给了main函数接收函数返回值的权利(其实用脚指头想都知道是在main里面析构的),不过用脚指头想不到的是,在 main 的什么部位析构,是像 t1、t2 一样在函数结束之后吗?

int main() {
	test t1;
	test t2;
	t2 = GetObject(t1);
	
	cout << "***********************************************" << endl;

	return 0;
}
test()
test()
test(const test&)
-----------------------------------------------
test()
~test()
operator =
~test()
***********************************************
~test()
~test()

事实证明,这个返回值生成的对象在赋值之后便被析构。


现在,我们将封闭的代码解封,开对比下面两段代码的结果

test GetObject(test t) {
	int val = t.getdata();
	cout << "-----------------------------------------------" << endl;
	test temp(val);		//多了这行
	cout << "-----------------------------------------------" << endl;
	return temp;
}

VS

test GetObject(test t) {
	int val = t.getdata();
	cout << "-----------------------------------------------" <<以上是关于C++编程经验:对象优化,试试?试试就逝世哈哈哈的主要内容,如果未能解决你的问题,请参考以下文章

社死天花板!连夜扛着火车逃离地球,本想试试大厂的面试,没想到直接逝世……

社死天花板!连夜扛着火车逃离地球,本想试试大厂的面试,没想到直接逝世……

社死天花板!连夜扛着火车逃离地球,本想试试大厂的面试,没想到直接逝世……

社死天花板!连夜扛着火车逃离地球,本想试试大厂的面试,没想到直接逝世……

day01_09.你已学会编程

资料哈代/拉马努金悼文