重载operator new/ operator delete
虽然C++ 标准库已经为我们提供了new 与delete 操作符的标准实现,但是由于缺乏对具体对象的具体分析,系统默认提供的分配器在时间和空间两方面都存在着一些问题:分配器速度较慢,而且在分配小型对象时空间浪费比较严重,特别是在一些对效率或内存有较大限制的特殊应用中。比如说在嵌入式的系统中,由于内存限制,频繁地进行不定大小的内存动态分配很可能会引起严重问题,甚至出现堆破碎的风险;再比如在游戏设计中,效率绝对是一个必须要考虑的问题,而标准new 与delete 操作符的实现却存在着天生的效率缺陷。此时,我们可以求助于new 与delete 操作符的重载,它们给程序带来更灵活的内存分配控制。除了改善效率,重载new 与delete 还可能存在以下两点原因:
检测代码中的内存错误。
获得内存使用的统计数据。
相对于其他的操作符,operator new 具有一定的特殊性,在多个方面上与它们大不相同。首先,对于用户自定义类型,如果不重载,其他操作符是无法使用的,而operator new 则不然,即使不重载,亦可用于用户自定义类型。其次,在参数方面,重载其他操作符时参数的个数必须是固定的,而operator new 的参数个数却可以是任意的,只需要保证第一个参数为size_t 类型,返回类型为void * 类型即可。所以operator new 的重载会给我们一种错觉:它更像是一个函数重载,而不是一个操作符重载。
重载的operator new 必须是类成员函数或全局函数,而不可以是某一名空间之内的函数或是全局静态函数。此外,还要多加注意的是,重载operator new 时需要兼容默认的 operator new 的错误处理方式,并且要满足C++ 的标准规定:当要求的内存大小为0byte 时也应该返回有效的内存地址。
为某个class 重载operator new 时必须将其定义为类的静态函数。因为operator new 是在类的具体对象被构建出来之前调用的,在调用operator new 的时候this 指针尚未诞生,因此重载的 operator new 必须是static 的
如果使用不同的参数类型重载operator new/delete,则请采用如下函数声明形式:
// 返回的指针必须能被普通的 ::operator delete(void*) 释放
void* operator new(size_t size, const char* file, int line);
// 析构函数抛异常时被调用
void operator delete(void* p, const char* file, int line);
调用时采用以下方式:
string* pStr = new (__FILE, __LINE__) string;
这样就能跟踪内存分配的具体位置,定位这个动作发生在哪个文件的哪一行代码中了。在“检测内存错误”和“统计内存使用数据”时通常会用这种方式重载。
2 用智能指针管理通过new 创建的对象