码迷,mamicode.com
首页 > 编程语言 > 详细

C++对象模型——解构语意学(第五章)

时间:2015-08-14 22:47:33      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:

5.4    对象的效率 (Object Efficiency)    

    在以下的效率测试中,对象构造和拷贝所需要的成本是以Point3d class声明为基准,从简单形式逐渐到复杂形式,包括Plain Ol‘ Data,抽象数据类型(ADT),单一继承,多重继承,虚拟继承,以下函数是测试的主角:
Point3d lots_of_copies(Point3d a, Point3d b) {
    Point3d pC = a;
    pC = b;                // 1
    b = a;                  // 2
    return pC;
}
    它内带四个memberwise初始化操作,包括两个参数,一个返回值以及一个局部对象pC,它也内带两个memberwise拷贝操作,分别是1和2的pC和b.main()函数如下:
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 = lots_of_copies(pA, pB);
    return 0;
}
    在最初两个程序中,数据类型是一个 struct 和一个拥有 public 数据的 class;
struct Point3d { float x, y, z; };
class Point3d { public: float x, y, z; };
    对pA和pB的初始化操作是通过 explicit initialization list来进行的:
Point3d pA = {1.725, 0.875, 0.478};
Point3d pB = {0.315, 0.317, 0.838};
    这两个操作表现出bitwise copy语意,所以应该可以预期它们的执行有最好的效率.
    "memberwise"初始化操作和拷贝操作(Initialization and Copy): Public Data Members和Bitwise Copy Semantics.
    CC的效率比较好,是因为NCC循环中产生了六个额外的汇编语言指令.这个额外负担并不会反映出任何特定的C++语意,这两个编译器的"中间C输出"大致是相等的.

5.5    解构语意学 (Semantics of Destruction)

    如果 class 没有定义destructor,那么只有在 class 内带的member object(或是 class 自己的base class)拥有destructor的情况下,编译器才会自动合成出一个.否则,destructor会被视为不需要,也就不需被合成(当然更不需要被调用).例如,Point,默认情况下就没有被编译器合成出一个destructor--虽然它拥有一个 virtual function:
class Point {
public:
    Point(float x = 0.0, float y = 0.0);
    Point(const Point &);
    virtual float z();
private:
    float _x, _y;
};
    类似的道理,如果把两个Point对象组合成一个Line class:
class Line {
public:
    Line(const Point &, const Point &);
    virtual draw();
protected:
    Point _begin, _end;
};
    Line也不会拥有一个合成出来的destructor,因为Point并没有destructor.
    当从Point派生出Point3d(即便是一种虚拟派生关联)时,如果没有声明一个destructor,编译器就没有必要合成一个destructor.
    不论Point或Point3d,都不需要destructor,为它们提供一个destructor反而不符合效率.应该拒绝那种"对称策略"的想法:"已经定义了一个constructor,所以感觉必须提供一个destructor".事实上,应该"需要"而非"感觉"来提供destructor,更不要因为不确定是否需要一个destructor,于是就提供它.
    为了决定 class 是否需要一个程序层面的destructor(或是constructor),请想想一个 class object的生命在哪里结束(开始)?需要什么操作才能保证对象的完整?这是写程序时比较需要了解的.这也是constructor和destructor什么时候起作用的关键.例如,已知:
{
    Point pt;
    Point *p = new Point3d;
    foo(&pt, p);
    delete p;
}
    可以看到,pt和p在作为foo()函数的参数之前,都必须先初始化为某些坐标值.这时候需要一个constructor,否则使用者必须明确地提供坐标值.一般而言,class 的使用者没办法检验一个local变量或heap变量以知道它们是否被初始化.把constructor想象为程序的一个额外负担是错误的,因为它们的工作有其必要性.如果没有它们,抽象化的使用就会有错误的倾向.
    当明确地 delete 掉p时会如何呢?在任何程序上必须处理的吗?是否需要在 delete 之前这么做:
p->x(0);
p->y(0);
    不,当然不需要.没有任何理由说明在 delete 一个对象之前先得将其内容清除干净.也不需要归还任何资源.在结束pt和p的生命之前,没有任何"class使用者层面"的程序操作是绝对必要的,因此,也就不一定需要一个destructor.
    然而考虑Vertex class,它维护了一个由紧邻的"顶点"所形成的链表,并且当一个顶点的生命结束时,在链表上来回移动以完成删除操作.如果这正是程序员所需要的,那这就是Vertex destructor的工作.
    当从Point3d和Vertex派生出Vertex3d时,如果不供应一个 explicit Vertex3d destructor,那么还是希望Vertex destructor被调用,以结束一个Vertex3d object.因此,编译器必须合成一个Vertex3d destructor,其唯一的任务就是调用Vertex destructor.如果提供一个Vertex3d destructor,编译器会扩展它,使它调用Vertex destructor.一个由程序员定义的destructor被扩展的方式类似constructors被扩展的方式,但顺序相反:
    1.如果object内带一个vptr,那么首先重设(reset)相关的 virtual table.
    2.destructor的函数本身现在被执行,也就是说vptr会在程序员的码执行前被重设(reset).
    3.如果 class 拥有member class objects,而后者拥有destructors,那么它们会以声明顺序的相反顺序被调用.
    4.如果有任何直接的(上一层)nonvirtual base classes拥有destructor,它们会以其声明顺序的相反顺序被调用.
    5.如果有任何的 virtual base classes拥有destructor,而当前讨论的这个 class 是最尾端(most-derived)的 class,那么它们会以其原来的构造顺序的相反顺序被调用
.
    (这个顺序似乎有问题,应该为2,3,1,4,5.其中1在2,3之后)
    就像constructor一样,目前对于destructor的一种最佳实现策略就是维护两份destructor实体:
    1.一个complete object实体,总是设定好vptr,并调用 virtual base class destructors.
    2.一个base class subobject实体:除非在destructor函数中调用一个 virtual function,否则它绝不会调用 virtual base class destructors并设定vptr.

    一个object的生命结束于其destructor开始执行之时,由于每一个base class destructor都轮番被调用,所以derived class 实际上变成了一个完整的object.例如一个PVertex对象归还其内存空间之前,会依次变成一个Vertex3d对象,一个Vertex对象,一个Point3d对象,最后成为一个Point对象.当在destructor中调用member functions时,对象的蜕变会因为vptr的重新设定(在每一个destructor中,在程序员所提供的代码之前)而受到影响.在程序中实施destructor的真正语言将在第6章详述.

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++对象模型——解构语意学(第五章)

标签:

原文地址:http://blog.csdn.net/yiranant/article/details/47668163

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!