存储耗尽

  自由存储运算符new、delete、new[]和delete[]通过一些在头文件<new>里描述的函数实现(19.4.5节):

    void* operator new(size_t);        // 为单个对象分配空间
    void operator delete(void*);
    void* operator new[](size_t);      // 为数组分配空间
    void operator delete[](void*);

当运算符new需要为某个对象分配空间时,它将调用operator new()去分配适当数量的字节。与此类似,当运算符new需要为一个数组分配空间时,就去调用operator new

  operator new()和operator new的标准实现并不对返回的存储做初始化。

  当new无法找到需要分配的空间时会发生什么情况呢?按照默认方式,这个分配函数将抛出一个bad_alloc异常(另一种情况见19.4.5节)。例如,

    void f()
    {
        try {
            for(;;) new char[10000];
        }
        catch(bad_alloc) {
            cerr << "Memory exhausted!\n";
        }
    }

无论我们能用的空间有多少,这一程序最终都会激活bad_alloc处理器。

  我们可以规定在存储耗尽时new应该去做什么。当new失败时,它将先去调用一个函数(如果存在),该函数是通过调用在 <new> 里声明的set_new_handler()设定的。例如,

    void out_of_store()
    {
        cerr << "operator new failed: out of store\n";
        throw bad_alloc();
    }

    int main()
    {
        set_new_handler(out_of_store);    // 将out_of_store()作为新的处理函数
        for(;;) new char[10000];
        cout << "done\n";
    }

这个程序不会到达写出done的地方。它将写出

operator new failed: out of store

參看14.4.5节关于operator new()的可能实现情况,它检查是否存在着能调用的处理函数,如果没有就抛出bad_alloc。new_hander有可能做出某些比简单地终止程序更聪明的事情。如果你知道new和delete是如何工作的---例如因为你提供了自己的operator new()和operator delete(),这个处理函数可能是企图去为new找到另一些存储并返回之。另一种方式是,某个用户可能提供一个废料收集器,使得delete的使用变成选择性的。当然,做这些事情都不是一个初学者的工作。对于所有需要自动废料收集器的人而言,应该做的正确事情是去获得一个已经写好并经过仔细测试的程序(C.9.1节)。

  通过提供new_handler,我们就处理了在程序中所有new的常规使用中对存储耗尽情况的检查。也存在另外两种控制存储分配的替代方法。我们可以为new的非标准使用提供非标准的分配函数和释放函数(15.6节),或者是依靠用户提供有关存储分配的附加信息(10.4.11节、19.4.5节)。

🔚