目录
1、通过重载获得内存管理权
之前的几章学习,是红色的路线。此时内存管理权限不在我们手中。
接下来,通过class内部的重载operator new/delete,我们可以获得内存管理权力。
注意operator new/delete,这张PPT里面有两个。一个是在class内部重载,还有一个是全局的重载。
2、容器的内存管理
当我们将元素放入容器中,容器显然也要做出与上面相似的内存分配的动作。
容器讲构造和析构函数包装在construct()与destroy()中。内存的分配和释放动作拉入分配器中。
分配器在分配内存的时候与上图的红色线路是一样的。
分配器所做的就是一些复杂的内存管理。
3、重载new、array new、replacement new,接管内存控制权
已知,我们可以从全局或者类里面去重载。
1、重载全局::operator new / ::operator delete以及array版本
注意这里的重载函数相对于原来的函数只是多了一个打印信息操作。
这里只是做一个接口的示范规格。
void* myAlloc(size_t size)
{
return malloc(size);
}
void myFree(void* ptr)
{
return free(ptr);
}
他们不能被声明于一个namespace内
inline void* operator new(size_t size)
{
cout << "global new()" << endl;
return myAlloc(size);
}
inline void operator delete(void* ptr)
{
cout << "global delete()" << endl;
myFree(ptr);
}
inline void* operator new[](size_t size)
{
cout << "global new[]()" << endl;
return myAlloc(size);
}
inline void operator delete[](void* ptr)
{
cout << "global delete[]()" << endl;
myFree();
}
2、在类里面去重载
我们在类里面写好两个重载函数:
class Foo {
public:
void* operator new(size_t);
void operator delete(void*,size_t);
};
注意上面的delete函数的第二个参数size_t是可有可无的。
同时也需要注意,这里的operator new和 operator delete 函数是静态的,要加上static。因为在new一个对象的时候我们手上是没有对象的,也就是说无法通过对象调用一般的函数。加上static就可以不通过对象而直接调用这两个函数了。这是一个细节。
在我们进行new和delete操作时,由编译器调用:
Foo* p = new Foo;
...
delete p;
编译器将上述代码转换为如下格式:
try {
void* mem = operator new(sizeof(Foo));
p = static_cast<Foo*>(mem);
//调用构造函数
p->Foo::Foo();
}
//调用析构函数
p->~Free();
operator delete(p);
同理array的版本如下:
Foo* p = new Foo[N];
...
delete [] p;
class Foo {
public:
void* operator new[](size_t);
void operator delete[](void*,size_t);
};