条款8: 写operator new和operator delete时要遵循常规
函数提供的行为要和系统缺省的operator new一致。
要有正确的返回值:如果内存分配请求成功,就返回指向内存的指针;如果失败,则遵循条款7的规定抛出一个std::bad_alloc类型的异常。
可用内存不够时要调用出错处理函数(见条款7);
处理好0字节内存请求的情况:c++标准要求,即使在请求分配0字节内存时,operator new也要返回一个合法指针。
此外,还要避免不小心隐藏了标准形式的new。
class base {
public:
static void * operator new(size_t size);
static void operator delete(void *rawmemory, size_t size);
...
};
void * base::operator new(size_t size){
if (size != sizeof(base)) // 如果数量“错误”,让标准operator new
return ::operator new(size); // 去处理这个请求
... // 否则处理这个请求
}
c++标准规定独立的(freestanding)类的大小都是非零值。
所以sizeof(x)永远不可能是零(即使x类没有成员),
#include
struct xxx { void func(); };
int main(){
printf("%lld\n", sizeof(xxx));//win10 vs2022 输出 1
return 0;
}
空基类优化(Empty Base Optimization,EBO)允许编译器在某些情境下省略空的基类的大小。实际还得看具体编译器的实现,所以最好用static_assert自检一下代码的设计期望。
这个其实用得少,具体要用时,找个标准代码抄一下。用的少,直接写出来还挺不容易的。
记得很久以前用过一个ibm官网上的一个new delete重载代码,实现内存泄漏的跟踪检查,原理就是重载了cpp标准库的new、delete所有接口,似乎有6个左右,然后相当于是设置了钩子函数,劫持了所有用户的new、delete操作(当然要注意确保所有被监控代码都使用了重载后的new、delete),然后用map存储了所有指针,程序结束时输出未释放的指针信息(主要是new所在的文件名、行号,及内存大小)。实际这种win下内存检测的方式并不好用,因为确保所有new、delete使用了重载的版本挺不容易的。好用的是vld。