深度探索c++对象模型第五章笔记下

5.3 对象复制语意学

如果我们设计一个class,并以一个class object指定给另一个class object时,我们有三个选择:

  • 1、什么都不做,因此得以实施默认行为;
  • 2、提供一个explicit copy assignment operator;
  • 3、明确地拒绝把一个class object指定给另一个class object;
    如果选择第3点,不准将一个class object指定给另一个class object,那么只要将copy assignment operator声明为private ,并且不提供其定义即可。
    把它设为private,我们就不再允许在任何地点(除了member functions以及class 的friends之中)进行赋值操作。
    不提供函数定义,则一旦某个member function或friend企图进行一份拷贝时,程序在链接时就会失败。

只有在默认行为所导致的语意不安全或不正确时,我们才需要设计一个copy assignment operator。

一个class 对于默认的copy assignment operator,在以下情况下不会表现出bitwise copy语意:

  • 1、当class内带一个member object,而其class有一个copy assignment operator时;
  • 2、当一个class的base class有一个copy assignment operator时;
  • 3、当一个class声明了任何virtual functions(我们一定不能够拷贝右端class object的vptr地址,因为他可能是一个derived class object)
  • 4、当class继承自一个virtual base class(不论此base class有没有copy operator)时。

我们是可能为程序提供一个copy constructor,为的是把Name return value(NRV)优化打开。

关于对象复制的建议:尽可能不要允许一个virtual base class的拷贝操作。或者更极端的一点是:不要在任何virtual base class中声明数据。

5.5 解构语意

如果class没有定义destructor,那么只有在class内带的member object拥有destructor的情况下,编译器才会自动合成一个destructor。否则,destructor会被视为不需要,也就不需要被合成。

关于constructor和destructor 并不存在 “对称策略”:“你已经定义了一个constructor,所以你必须要提供一个destructor” 。我们要根据程序的“需要”来提供destructor,而不是我们的感觉。
为了决定class是否需要一个程序层面的destructor(或是constructor),我们需要思考这个class的object的生命周期一般都是在哪里结束(开始)?需要怎样的操作才能保证对象的完整?

{
	Point pt;
	Point *p=new Point3d();
	foo(&pt,p);
	...
	delete p;
}

在这里可以看到,pt和p在作为foo函数的参数之前,都必须先初始化为某些坐标值。这时候需要一个constructor,否则使用者必须明确地提供坐标值。
就像construtor一样,目前对于destrutor的一种最佳实现策略就是维护两份destructor实体:

  • 1、一个complete object实体,总是设定好vptr(s),并调用virtual base class destrutors;
  • 2、一个base class subobject实体;除非在destrutor函数中调用一个virtual function,否则它绝不会调用virtual base class destructor并设定vptr。

一个object的生命周期结束于其destructor开始执行之时。由于每一个base class destructor都被轮番调用。所以derived object实际上就变成了一个完整的object。例如,一个PVertex对象归还其内存空间之前,会一次变成一个Vertex3d对象,一个Vertex对象,一个Point3d对象,最后变成一个Pointe对象。
当我们在destructor中调用member functions时,对象的蜕变会因为vptr的重新设定而受到影响。

一个由程序员定义的destructor被扩展的方式类似constructors被扩展的方式,但顺序相反:

  • 1、destrutor的函数本身首先被执行;
  • 2、如果class拥有member class objects,而后者拥有destructors,那么它们会以其声明顺序的相反顺序被调用。
  • 3、如果object内带一个vptr,则现在被重新设定,指向适当之base class的virtual table。
  • 4、如果有任何直接的(上一层)nonvirtual base classed 拥有destructor,它们会以其声明顺序的相反顺序被调用。
  • 5、如果有任何virtual base classes拥有destructor,而当前讨论的这个class是最尾端(most-derived)的class,那么它们就会以原来的构造顺序的相反顺序被调用。

猜你喜欢

转载自blog.csdn.net/weixin_39116058/article/details/85164830