5.4 对象的效能(Object Efficiency)

以下的效率测试中,对象构造和拷贝所需的成本是以Point3d class声明为基础,从简单形式逐渐到复杂形式,包括Plain OI' Data、抽象数据类型(ADT)、单一继承、多重继承、虚拟继承。以下是测试的主角:

Point3d lots_of_copies(Point3d a,Point3d b)
{
	Point3d pC = a;
	
	pC = b;//(1)
	b = a; //(2)
	
	return pC;
}

main()
{
	Point3d pA(1.725,0.875,0.478);
	Point3d pB(0.315,0.317,0.838);
	Point3d pc;
	for(int iters = 0; iters < 10000000;iters++)
			pC = lost_of_copies(pA,pB);
}

最初的两个程序中,一个是struct和一个public数据的class,对pA和平B的初始化操作explicit initialization list进行的:

struct Point3d{float x,float y,float z;};
class Point3d{public: float x,float y,float z;};

Point3d pA = {1.725,0.875,0.478};
Point3d pB = {0.315,0.317,0.838};

这两个操作表现出bitwise copy语意,所以应该会预期它们的执行效率最好:

下一个测试,唯一的改变是数据的封装以及inline函数使用,以及一个inline constructor,用以初始化每一个object。class仍然表现bitwise copy语意,所以执行效率应该相同,事实上则有些差距:

 

效率上的差异并不是因为lots_of_copies(), 而是因为main()函数中的class object的初始化操作。修改struct的初始化操作如下,并复制inline class constructor的扩展部分:

main()
{
	Point3d pA;
	pA.x = 1.725;pA.y = 0.875;pA.z = 0.478;
	
	Point3d pB;
	pB.x = 0.315;pB.y = 0.317;pB.z = 0.838;
	
	//其余相同
}

它们现在封装后的class表现方式,时间都增加了:

经由constructor的inline expansion(扩充),坐标成员的初始化操作带来以下两个指令的汇编码:一个指令将常量加载到寄存器,另一个指令做真正的存储操作;坐标成员经由explicit initialization list来做初始化操作,会得到单一指令,因为常量值已经被预先加载好了。

封装和为封装的两个Pointd3d声明之间,另一个差异就是:

Point3d pc;

如果使用ADT表现法,pC会以其default constructor的inline expansion自动进行初始化——甚至在此例而言,没有初始化也很安全。即使加上了封装,还是完全相当于C程序中的直接存储数据。

下一个测试,把Pointd3d分割成三个层次的单一继承:

class Point1d{}; //_x
class Point2d : public Point1d{}; //_y
class Point3d : public Point2d{}; //_z

没有任何virtual functions。由于Point3d仍展现出bitwise copy语意,所以额外的单一继承不应该影响“memberwise对象初始化或拷贝操作“的成本:

下面多重继承设计:

class Point1d{}; //_x
class Point2d{}; //_y
class Point3d : public Point1d,public Point2d{};//_z

 由于Pointd class 仍然显示出bitwise copy语意,所以额外的多重继承关系不应该再memberwise的对象初始化操作或拷贝上增加成本:

截止目前的所有测试,所有版本的差异都是以“初始化三个local objects”为中心,而不是以“memberwise initialization和copy的损耗” 为中心。这些操作的完成都是一成不变的,都支持“bitwise copy”语意。但是导入虚拟继承,情况就改变了,下吗是单层虚拟继承:

class Point1d{};
class Point2d : public virtual Point1d{...};
class Point3d : public Point2d{...};

不再允许class有用bitwise copy语意(第一次虚拟继承不允许,第二层继承更加复杂)。合成的inline copy constructor和copy assignment operator派上用场,导致效率成本重大增加:

如果在前面那种(ADT):有着封装并加上一个virtual function的class声明。这种情况下不允许 bitwise copy语意,合成的inline copy constructor和copy assignment operator被产生出来,效率成本的增加不如预期,但比起bitwise copy却也有大约40%~50%。如果这个函数是程序员提供的一个non-inline函数,成本更高:

 下面测试采用其他有着bitwise copy语意的表现方式,取代inline合成的memberwise copy constructor和copy assignment operator。这一次反映出来是对象构造和拷贝的成本,原因是继承体系的复杂度增加了:

猜你喜欢

转载自blog.csdn.net/weixin_28712713/article/details/84578020
5.4
今日推荐