C++的delete以及operator delete重载。
朝花
刚学习c++的时候就学过在c++中delete/new其实都是一个方法,我们执行delete p
其实就是调用了方法operator delete(p);
当然,还学过delete/new有全局的和局部的(类中的),我们可以重载他们,让delete和new按照我们想要的样子去执行对象的创建和销毁。
在过去这么多年中,我一直认坚定的认为我们代码中的delete p
,等价于 operator delete(void*)
。并幼稚的认为析构器的调用是在operator delete(void*)
方法之后。
震惊!
为了维护一段年久的代码,我需要继承Base
类创造一个新的Drive
类,同时在现有代码中,之前用到Base类的地方都会在用完后delete pBase;
而新创造的Drive
类是不需要/不能被释放的,这时候问题就来了:类似delete pBase;
这样代码有成百上千处,分布在不同部门维护的不同模块代码中,真的没有办法去优雅的修改整个Base类的构造/释放用法。
于是,这时最简单粗暴的想法就是让delete pBase;
在实例是Drive
时失效。理所当然的想法就是重载operator delete,添加一个内部标记,只有标记为可释放时,delete才能真正的干活。
但,现实总是比想象骨感。
自信满满的编译代码,运行。程序并没有按照想要的样子运行。这时才发现:
delete pBase;
不是 Base::operator delete(pBase)
delete pBase;
不是 Base::operator delete(pBase)
delete pBase;
不是 Base::operator delete(pBase)
delete pBase
中delete是一个c++关键字!
它在delete pBase
这一表达式中,表示这里要销毁pBase指向的对象。
于是delete
会先调用Drive
的析构函数,然后是Base
的析构函数,然后才是operator delete()
的调用。这个顺序非常重要!operator delete()在析构函数之后调用!所以咱真的没法通过重载operator delete()
来阻止delete pBase
的执行。
当然,我们如果在析构函数和operator delete()中都添加一个标志,让他们什么事都不干呢?理论上这样确实可以阻止对象的销毁,更准确的说是delete pBase
之后,pBase指向的对象还在内存空间上(win10 vs2012 x64 测试),但是c++标准对于这样的行为是没有定义的,(我们有找到,没有确切的证据能让我说服自己可以把这样的代码提交出去)。
做个总结吧
- delete 是c++关键字,不能与delete操作符划等号。
- delete关键字背后会调用析构函数和delete操作符方法,且析构函数执行在先。
- 当你发现你的子类中的方法与父类同名方法的使用模式/行为模式不一致,这说明你的代码设计是有问题的。这时多态的封装事实上已经被破坏。