C++对象的优化--减少不必要的函数调用

2022-02-25 08:44:17 浏览数 (1)

测试环境:win10 vs2013 初始代码:

代码语言:javascript复制
#include <iostream>
using namespace std;


class Test {
private:
	int ma;
public:
	Test(int data = 10) :ma(data) {
		cout << "Test(int)" << endl;
	}

	Test(const Test& t) :ma(t.ma) {
		cout << "Test(const Test&)" << endl;
	}

	~Test() {
		cout << "~Test()" << endl;
	}

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

	int getData() {
		return ma;
	}
};


Test getObject(Test t) {
	int val = t.getData();
	Test res(val);
	return res;
}

int main() {
	Test t1(10);
	Test t2;

	t2 = getObject(t1);
	return 0;
}

执行结果: 上面短短的三行代码,背后居然11次的函数调用,效率太低了!!!

一、函数参数要求传入对象时,使用引用传递

代码语言:javascript复制
#include <iostream>
using namespace std;


class Test {
private:
	int ma;
public:
	Test(int data = 10) :ma(data) {
		cout << "Test(int)" << endl;
	}
		
	Test(const Test& t) :ma(t.ma) {
		cout << "Test(const Test&)" << endl;
	}

	~Test() {
		cout << "~Test()" << endl;
	}

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

	int getData() {
		return ma;
	}
};

// 相对上边的代码 仅仅是将形式参数 Test t改为Test &t
Test getObject(Test& t) {
	int val = t.getData();
	Test res(val);
	return res;
}

int main() {
	Test t1(10);
	Test t2;

	t2 = getObject(t1);
	return 0;
}

执行结果:

可以看到,经过函数参数的优化(值传递->引用传递),减少了一次临时对象构造和析构的函数开销。 相对于之前,只有9次的函数调用,减少了两次!!!

二、函数返回时,返回临时对象,不要先定义对象,然后再返回。直接提前计算好构造该函数返回对象所需要的参数,直接返回临时对象。

代码语言:javascript复制
#include <iostream>
using namespace std;


class Test {
private:
	int ma;
public:
	Test(int data = 10) :ma(data) {
		cout << "Test(int)" << endl;
	}

	Test(const Test& t) :ma(t.ma) {
		cout << "Test(const Test&)" << endl;
	}

	~Test() {
		cout << "~Test()" << endl;
	}

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

	int getData() {
		return ma;
	}
};


Test getObject(Test &t) {
	int val = t.getData();
	// Test res(val);
	// return res;
	return Test(val);
}

int main() {
	Test t1(10);
	Test t2;

	t2 = getObject(t1);
	return 0;
}

执行结果:

相对于上一步优化,又减少了两次函数调用的开销!!!

三、当需要接受一个函数的返回值时,并且该返回值是一个对象,不要以赋值的方式接受,以初始化的方式接受。

代码语言:javascript复制
#include <iostream>
using namespace std;


class Test {
private:
	int ma;
public:
	Test(int data = 10) :ma(data) {
		cout << "Test(int)" << endl;
	}

	Test(const Test& t) :ma(t.ma) {
		cout << "Test(const Test&)" << endl;
	}

	~Test() {
		cout << "~Test()" << endl;
	}

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

	int getData() {
		return ma;
	}
};


Test getObject(Test &t) {
	int val = t.getData();
	// Test res(val);
	// return res;
	return Test(val);
}

int main() {
	Test t1(10);
	Test t2 = getObject(t1);// 初始化的方式接受

	// t2 = getObject(t1); // 赋值的方式接受
	return 0;
}

执行结果:

相对于初始的代码,同样是获取一个对象的功能,优化到现在只有两次的构造和两次析构的调用,程序减少了相当大的一部分的函数调用开销,程序的效率也得到了很大的提升。一次调用getObejct()函数可以减少7次的函数调用开销,那么100万次的调用,就能减少700万次的开销。量变产生质变!!! 对象优化的三条规则 1.当函数的形式参数需要传递对象时,不要用值接受,用引用接受。减少一次临时对象的构造和析构。 2.当函数的返回值为对象时,不要再函数题先定义好零时对象,然后再返回值。直接提前计算好构造该返回对象需要的参数,直接返回一个临时对象。 3.当接受函数返回值为对象的函数的返回值时,以初始化的方式接受,不要以赋值的方式接受。 tips:当以临时对象拷贝构造一个新对象时,编译器不会产生这个临时对象,直接以构造临时对象的方式直接构造新对象,减少一次临时对象的构造和析构。

0 人点赞