[原创文章欢迎转载,但请保留作者信息]
Justin 于 2010-06-02
上堂课说的是重载new和delete的需要,今天大师开讲在写new和delete时需要注意的问题。
课堂笔记如下:
对于new
- C++要求new操作符可以接受0字节的分配。书中给出的方法是当成分配一个字节来处理,理由是这样简单,合法,可以工作,而且不会有多少人真的要分配0字节的内存。不深究了,不然太钻牛角尖了。
- new的过程应该是个无限循环,跳出循环的途径只有:
- 成功分配了内存
- 想方设法“挤”出内存来分配,“安装”另外一个new handler继续处理,或是抛出异常。
- 要考虑到为某个类写的new操作会可能被其子类继承。在前几天的49课中大师有提到可以为一个类(比如aClass)量身订作其专属的new和new handler,尤其是new函数,作者有可能在编写的时候利用了其专属类的大小(比如sizeof(aClass))做了一些优化。这种优化是专对于这一个类的,如果用在其子类中就几乎肯定要出问题,因为子类的大小一般而言比基类要大。
解决办法之一就是在new函数的入口处添加下面的判断:
void *aClass::operator new(std::size_t size) throw(std::bad_alloc)
{
if (size != sizeof(aClass))
return ::operator new(size);
// ok, we are "newing" an aClass object, go ahead..
}
当判断结果为假时,就放弃使用类专属的new函数,让“标配”的new函数去处理。
- 当需要编写operator new[]时,情况变得更加复杂:
- 你的new[]函数可能会被用于批量分配一组内存,声称是给基类对象的,到了后面却有一些被子类对象使用。如前所述两者大小不一样,于是你不能假设aClass::operator new[]中的size就是sizeof(aClass)。
- 抛开第一点不谈,传给new[]函数的size还不一定是用来存放一个类对象的大小,因为当要分配一组内存的时候,有些平台上会要求额外的空间来存放数组的大小。
很可惜大师没有给出具体的例子来解决上面的问题,也许是需要具体问题具体分析的吧。
对于delete
- 类似的,C++也要求可以delete一个空内存(null pointer),在delete中就简单多了,如果是空,就直接返回。
- 同样的,对于某个类的专属delete函数,在入口处需要判断一下将要释放内存的大小是否和该类对象的大小一致,如果不一致,就交给“标配”的delete函数去处理。踢皮球,很简单@#¥%
- 如果一个类的delete函数用于释放其子类的对象内存,基本上来说就会出错,因为基类和子类对delete来说是完全不同的对象类型。解决的办法不在delete函数,而在于基类的析构函数要写成虚函数。