Effective C++ 条款51

编写new和delete时需固守常规

本章节介绍在自定义new和delete函数时,应该需要遵守哪些要求,为什么遵守这些要求。

首先,如下代码所述,当我们定义new的时候需要把size为0的内存申请考虑进去,为什么当内存申请为0时却分配1个字节的内存。大家想一下当你定义一个空的classA时,sizeof(A)占据大小是多小?很显然占据1个字节的空间,这是系统分配内存时在这种情况下遵守的规则,我们可以自定义自己的new,但是前提要迎合系统的规则。事实上,这样做是为了让语言其他部分方便操作。考虑byte为0的情况之后,我们开始分配内存空间,如果分配成功我们就返回什么的内存地址,如果分配失败我们就需要调用new-handler函数进行分配失败后的处理,这个函数的用处一般情况下就是释放一部分内存,重新尝试内存分配。我们设分配过程在一个无限循环里,所以真正写程序的时候肯定要有退出循环的语句,正如条款49提出的哪些方法。

void* operator new(std::size_t size) throw(std::bad_alloc)
{
    using namespace std;
    if(size==0){//处理0-byte申请
        size=1;
    }
    while(true){
        尝试分配size bytes;
        if(分配成功)
            return 指向分配得来的内存;
        //分配失败,找到当前的new-handling函数
        new_handler globalHandler=set_new_handler(0);
        set_new_handler(globalHandler);

        if(globalHandler) (*globalHandler)();
        else throw std::bad_alloc();
    }
}

正如条款50所说,我们定义内存分配器是为了特定的class对象,以此来优化,所以我们往往将内存分配器的功能封装在base class中,如下代码:

class Base{
public:
    static void* operator new(std::size_t size) throw(std::bad_alloc)
    ……
};
class Derived:public Base
{……};//假设为重新定义operator new
Derived* p=new Derived;//这里调用了Base::operator new

如果是class专属的operator new,应该改为这样:

void* Base::operator new(std::size_t size) throw(std::bad_alloc)
{
    if(size!=sizeof(Base))
        return ::operator new(size);//使用标准的operator new
    ……
}

接着,事实上,由于base class一般都会比derived class小,所以,当申请大小不满足derived class时,我们调用标准的内存分配器。

然后,对于class专属版的arrays内存分配,需要实现operator new[]。编写operator new[]时,唯一要做的一件事就是分配一块未加工的内存(raw memory),而且内存足够大,因为你无法对array之内迄今尚未存在的元素对象做任何事。甚至我们无法知道这个array含有多少个元素对象。可能你也不知道每个对象多大,因为base class的operator new[]有可能经由继承被调用,将内存分配给derived class对象的array使用。所以不能再Base::operator new[]中假设每个元素对象大小是sizeof(Base),这样就是说你不能假设array元素个数是(bytes申请数/sizeof(Base))。此外,传递给operator new[]的size_t参数,其值有可能比将辈填对象的内存大一些,因为条款 16提过,动态分配的arrays可能包含额外空间用来存放元素个数。

其次,C++保证删除指针永远安全,所以在程序中,我们对于null指针的操作如下代码:

void operator delete(void* rawMemory) throw()
{
    if(rawMemory==0) return;

    归还rawMemory所指内存;
}

最后,,我们要始终记得new和delete的对立,new的处理方式和delete的处理方式要交相呼应。如下代码:

void Base::operator delete(void rawMemory, std::size_t size) throw()
{
    if(rawMemory==0) return;
    if(size!=sizeof(Base)){
        ::operator delete(rawMemory);
        return ;
    }
    归还rawMemory所指内存;
    return ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值