• Effective C++ 条款51 编写new和delete时需固守常规


    1. 实现定制的operator new和operator delete需要满足一定的要求.

        以operator new而言:实现一致性operator new必须返回正确的值;内存不足时必得调用new-handling函数;必须有对付零内存需求的准备;需避免不慎掩盖正常形式的new;如果有能力供应客户申请的内存,就返回一个指针指向该内存,反之就遵循条款49的规则并抛出bad_alloc异常;应该内含一个无限循环,知道成功分配内存或new-handling完成其功能......

        以上的要求中"必须有对付零内存需求的准备"指的是即使客户要求0 bytes,operator也得返回一个合法指针.

    2. 下面是一个non-member operator new伪码:

    void* operator new(std::size_t size) throw(std::bad_alloc){
        using namespace std;
        if(size==0)
            size=1;
        while(true){
            尝试分配size bytes;
            if(分配成功)
                return(一个指针,指向分配而来的内存);
            new_handler globalHandler=set_new_handler(0);
            set_new_handler(globalHandler);
            if(globalHandler)
                (*globalHandler)();
            else
                throw std::bad_alloc();
        }
    }
    View Code

        需要注意的是,operator new成员函数会被derived classes继承,这会导致某些有趣的复杂度.写出定制型内存管理器的一个常见理由是为针对某特定class的对象分配行为提供最优化,而不是为了该class的任何derived class,也就是说,这对某个类设计的operator,其行为可能很典型的只为大小刚好为该类型对象代销大小而设计.然而一旦被继承下去,有可能base class的operator new被调用用以分配derived class对象:

    class Base{
    public:
        static void* operator new(std::size_t size) throw(std::bad_alloc);
        ...
    };
    class Derived:public Base{
       ...
    };
    Derived*p =new Derived; //这里调用的是Base::operaotr new!
    View Code

        Base class专属之operator new往往并不是被用来为Derived class对象分配内存,解决方法就是在"内存申请量错误"的调用行为改采标准的operator new:

    void * Base::operator new(std::size_t size) throw(std::bad_alloc){
        if(size!=sizeof(Base))
            return ::operator new(size);
        ...
    }
    View Code

        如果要实现operator new[]的定制版,那么operator new[]唯一要做的就是分配一块内存,而无法对array内尚未存在的元素做任何事情,设置无法计算每个元素对象有多大,实际上,C++标准中operator new[]的缺省操作是经由operator new完成的(http://www.cplusplus.com/reference/new/operator%20new[]/?kw=operator%20new[]).

        operator delete的情况比较简单,唯一需要注意的是C++保证"删除null指针永远安全",下面是non-member operator delete的伪码:

    void operator delete(void* rawMemory) throw(){
        if(rawMemory==0)
            return;
        归还rawMemory所指内存;
    }
    View Code

        operator delete的member版本也比较简单,只需要多加一个动作检查删除数量.万一class专属的operator new将大小有误的分配行为转交::operator new执行,大小有误的删除行为也必须转交::operator delete执行:

    class Base{
    public:
        static void* operator new(std::size_t size) throw(std::bad_alloc);
        static void operator delete(void* rawMemory,str::size_t size) throw();
        ...
    };
    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;
    }
    View Code

        需要注意的是,如果即将被删除的对象派生自某个base class而后者欠缺virtual析构函数,那么C++传给operator delete的size_t数值可能不正确.也就是说,operator delete的正常运作依赖于析构函数的正常运作(如果有析构函数的话).

  • 相关阅读:
    Mybatis
    spring2
    servlet
    MyBatis1
    Docker容器保存为镜像文件并发布到DockerHub上
    【JS】提取字符串中的分数,汇总后算出平均分,并与每个分数比较,输出
    CentOS下创建管理员权限用户
    Centos安装文件传输软件rz sz
    2022年的零日漏洞影响了哪些平台?
    关于渗透测试的优缺点,你知道吗?
  • 原文地址:https://www.cnblogs.com/reasno/p/4803967.html
Copyright © 2020-2023  润新知