以下的效率测试中,对象构造和拷贝所需的成本是以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。这一次反映出来是对象构造和拷贝的成本,原因是继承体系的复杂度增加了: