如果正在删除的对象指针是0,将不发生任何事情
内存管理的开销
1.调用malloc(),从堆里申请一块内存
2.从堆里搜索出一块足够满足请求的内存。可以挺过检查显示内存使用情况的某种图或目录来实现搜索。这个过程很快,但可能要试探几次。
3.在指向这块内存的指针返回之前,这块内存大小和地址必须记录下来,这样以后调用malloc()时就不会再使用它了,而且当调用free()时,系统就会知道要释放多大的内存。
用完内存
当运算符new找不到足够大的连续内存块来安排对象时将会发生什么?一个称为new-handle的函数被调用,或者检查指向函数的指针,如果指针非零,那么它指向的函数被调用。
对于new-handler的缺省动作是抛出一个异常。然而,如果在程序里用堆分配,至少要用“内存已用完”的信息代替new-handler,并异常中断程序。
通过包含new.h,然后以想装入的函数地址作为参数调用set_new_handler()函数,这样就替换了new-handler
#include <iostream>
#include <stdlib.h>
#include <new.h>
using namespace::std;
void out_of_memory() {
cerr << "memory exhausted!" << endl;
exit(1);
}
int main() {
set_new_handler(out_of_memory);
while(1)
new int[1000]; //Exhausted memory
}
重载new和delete
当重载运算符new和delete时,记住只改变原有的内存分配方法是很重要的。编译器将用new代替缺省的版本去分配内存,然后为那个内存调用构造函数。所以,虽然编译器遇到new时会分配内存并调用构造函数,但当我们重载new时,可以改变的只是内存分配部分。
当重载运算符new时,也可以替换它用完内存时的行为,所以必须在运算符new里决定做什么:返回0、写一个调用new-handler的循环、再试着分配或用一个bad_alloc异常处理
重载全局new和delete
当全局版本的 new和delete不能满足整个系统时,对其重载是很极端的方法。如果重载全局版本,那么缺省版本就完全不能被访问--甚至在这个重载定义里也不能调用他们。
重载的new必须有一个size_t参数,返回值是一个void*。
运算符delete接受一个指向由new分配的内存的void*,返回值是void。
#include <stdio.h>
#include <stdlib.h>
void* operator new(size_t sz) {
void* m = malloc(sz);
return m;
}
void operator delete(void* m) {
free(m);
}
为一个类重载new和delete
为一个类创建new和delete时,不必说明是static,我们仍然是在创建static成员函数。当编译器看到使用new创建类对象时,它选择成员版运算符new而不是全局版的new。但全局版的new和delete为所有其他类型对象使用。(除非他们有自己的new和delete)。
对象纺织
重载运算符new还有其他两个不常见用途:
1.可能想要在内存 的指定位置上放置一个对象
2.可能想在调用new时,可以从不同的内存分配器中选择
这两种情形都用相同的机制解决:重载运算符new可以带多于一个的参数
#include <stddef.h>
#include <iostream>
using namespace::std;
class X {
int i;
public:
X(int I = 0) : i(I) {}
~X() {
cout << "X::~X()" << endl;
}
void* operator new(size_t, void* loc) {
return loc;
}
};
int main() {
int l[10];
X* xp = new(l) X(47);
xp->X::~X();
}