| ||||
| 其实所谓的delete分为两步,runtime在遇到一个delete的时候,理论上会调用一个叫做delete operator的东西,这个东西会先调用dtor,然后调用operator delete来释放内存。我们能够重载的是operator delete,而delete operator是无法重载的。 对于operator delete来说,它接受一个void*为参数,它只负责释放内存。那么,按照你的layout,pb1和d指向的内存地址肯定是不一样的,由于Base1有大小,pb2会有一个偏移。因此,对于operator delete来说,如果你传给它pb2,它就直接over了。 那么,delete operator怎么可以知道应该怎样传递正确地传递地址过去呢?这是因为,delete operator有点类似于virtual的。要实现这个virtual特性的先决条件就是,你的dtor必须是virtual的。这就可以解释为什么你把virtual注释了,就会over。 至于你把f也注释了,就不crash了。这个原因可能有多种多样的。也许仍然会crash,也许因为优化的原因,....。但是这个仍然是不对的,不能因为不crash就这样用。 |
| ||||
| 我刚才在每个类里加了两个输出用于查看指针位置: c++ 代码:
Derived new: 0x6a02a8 f Base2 del: 0x6a02ac 11946 [sig] a 3356 _cygtls::handle_exceptions: ... 所以pb1, pb2和p实际指向的位置是不同的。 而如果,调用delete pb1,就会显示: Derived new: 0x6a02a8 f Derive dtor Derived del: 0x6a02a8 程序正确的进入了子类的operator delete,而不是进入了pb1的operator delete 有趣的是,这是个多重继承,如果把Base2的virtual dtor打开,并且delete pb2,则程序输出: Derived new: 0x6a02a8 f Derive dtor Base2 dtor Base1 dtor Derived del: 0x6a02a8 注意到:第一父类Base1的dtor也被调用了。这里面vtable是什么样子呢? |
| ||||
| 哦,顺便说一下最开始这个程序的应用背景。 本来我对单根继承下的virtual dtor和对应的vtable实现感觉自己理解还算清楚。不过看到了我们正在使用的框架规则,就感觉有怀疑了。 这个框架,对于所有堆上的对象,有一个公共基类CBase,方便内存管理。只要是从基类派生出来的子类,new出来后,只要放到到一个管理器内,就不用管了。 但是,有一个规则说:如果不是从这个基类派生出来的,那么如果new出来后,也放到管理器内,就会有麻烦。我觉得这个也能理解,因为这个管理器很可能内部维护了一个CBase*的指针容器,它在释放对象时,遍历容器,调用delete,例如: c++ 代码:
同时,我浏览框架代码,发现很多接口类,并没有定义virutal dtor,因此,如果是多继承,比如定义了一些接口Interface1, Interface2, 然后子类,继承CBase,实现Interface1和2,然后再把指向接口的指针放入管理器;那么就会像最前面的例子程序一样,crash。 |
| ||||
| 我看了下管理器的代码,有个重载的版本,接受void*指针的对象。释放时,仅仅free内存,而不调用dtor。如果希望释放时调用dtor,就需要通过模板把类型信息告诉管理器: c++ 代码:
另外,我正在google这些问题:多继承时vtable是什么样子的?为什么对着Base2的指针delete,Base1的dtor也会得到调用?如果所有基类都有virutal dtor,那么就会按照继承树的关系一层一层调用到所有基类,届时各个兄弟基类dtor的调用顺序会是什么样子的? 此帖于 2008-07-28 07:42 PM 被 liuxinyu 编辑. |
| ||||
| 查了一下, 多继承的情况下,对象在构造时,依照深度优先,从左向右遍历继承树进行构造。 在析构时,按照和构造正好相反的顺序[1] vtable是这样的,子类的memory layout中,有n个直接父类的vtable,每个vtable中都有一个dtor的指针,[2]这样,任何一个父类声明了vdtor,都可以正确调用到子类的dtor。然后,按照上述规则沿着继承树析构,依次调用所有父类的dtor 最后一步,就是按照pora描述的,调用子类的operator delete释放内存。 -- [1]: [25] Inheritance -- multiple and virtual inheritance, C++ FAQ Lite [2]: Virtual method table - Wikipedia, the free encyclopedia 此帖于 2008-07-28 08:23 PM 被 liuxinyu 编辑. |