• new和delete2


    new
    平常使用的new都是new operator(new操作符),它是语言内置的,无法重载。
    new的第一种写法:
    //call new operator
    int *= new int(3);

    调用new operator后做了两件事:
    1、调用operator new分配内存。
    2、调用构造函数初始化对象。
    operator new声明如下:

    //operator new's declaration
    void * operator new(size_t size);

    它可以被重载,但是第一个参数类型必须是size_t, 决定分配内存的大小。
    可以调用operator new只进行内存分配:

    //call operator new
    void *= operator new(4);


    new的第二种写法:

    //another way of calling new operator
    int *= new(v)int(5);
    调用new operator后做了两件事:
    1、调用placement new,这里不分配内存,只返回传入的指向内存的指针。
    2、调用构造函数初始化对象。
    placement new的实现可能像这样:
    //placement new
    void * operator new(size_t, void *location)
    {
        
    return location;
    }
    全局的placement new不能被重载,也就是说无法定义声明为 void* operator new(size_t, void* ) 的函数。


    new的第三种写法:
    //array
    int *= new int[4];
    调用new operator后做了两件事:
    1、调用operator new[],分配内存。
    2、对数组里的每一个对象调用构造函数。
    可重载,声明如下:
    //operator new[]'s declaration
    void* operator new[](size_t);


    delete:
    平常使用的delete是delete operator(delete操作符),不能被重载。
    delete的第一种写法:
    //delete operator
    delete p;

    调用delete operator时做了如下两件事:
    1、调用析构函数。
    2、调用operator delete释放内存。

    operator delete声明如下:

    //operator delete's declaration
    void operator delete(void *p)

    operator delete只释放内存,不调用析构函数,可以被重载,可以像这样调用:

    //call operator delete
    operator delete(p);

    delete的第二种写法:

    //array
    delete[] p;

    调用delete operator时做了如下两件事:
    1、对数组里的每个对象调用析构函数。
    2、调用operator delete[]释放内存。
    可重载,声明如下:

    //operator delete[]'s declaration
    void operator delete[](void* p)



     
    内存分配失败时的情况
    使用new分配内存失败时会抛出异常std::bad_alloc,所以如下if条件不会满足:

    int *= new int;
    if(NULL == p)                            //此条件不会满足
    若用这种方式,则内存分配失败时不会抛出异常,返回空指针:
    int *= new(nothrow) int;     //类似placement new的new operator调用
    if(NULL == p)                           //此条件可能满足

    set_new_handler可以用来设置operator new分配内存出错时所调用的错误处理函数,它在<new>中声明如下:
    typedef void (* new_handler) ();
    new_handler set_new_handler(new_handler) 
    throw ();
    new_handler是指向错误处理函数的函数指针。
    当用operator new分配内存失败时,首先调用set_new_handler设置的错误处理函数,然后抛出std::bad_alloc异常。
    所以可以通过重载operator new和set_new_handler,针对某一个类,设置特定的内存分配错误时的处理,而不影响全局的new_handler,实现如下:
    class Allocate
    {
    public:
        
    //重载set_new_handler,设置自己的内存分配错误处理函数
        static new_handler set_new_handler(new_handler p);

        
    //重载operator new,在异常抛出前或者成功返回前恢复全局的new_handler
        static void* operator new(size_t size);

    private:
        
    //保存自己的内存分配错误处理函数
        static new_handler    current_handler;
    }
    ;

    //初始化类的static数据成员
    new_handler Allocate::current_handler = NULL;

    //重载set_new_handler
    new_handler Allocate::set_new_handler(new_handler p)
    {
        
    //保存当前传入的new_handler,返回之前的new_handler
        new_handler old_handler = current_handler;
        current_handler 
    = p;
        
    return old_handler;
    }


    //重载operator new
    void* Allocate::operator new(size_t size)
    {
        
    //保存全局的new_handler,传入当前的new_handler
        new_handler globe_handler = std::set_new_handler(current_handler);
        
        
    void *memory = NULL;
        
    try
        
    {    
            
    //调用全局的operator new分配内存
            memory = ::operator new(size);
        }

        
    catch(std::bad_alloc)
        
    {
            
    //分配内存失败,抛出异常前已经调用了前面设置的new_handler
            
    //现在恢复之前的全局new_handler,并rethrow异常
            std::set_new_handler(globe_handler);
            
    throw;
        }

        
    //内存分配成功,恢复全局的new_handler
        std::set_new_handler(globe_handler);
        
    return memory;
    }

    重载set_new_handler使别人可以为这个类设置内存分配出错的处理函数。
    重载operator new先用此类的new_handler替换了全局的new_handler,保证operator new分配内存失败时会调用自己的错误处理函数,
    在离开前恢复全局的new_handler,保证其它类型的operator new失败时还会使用全局的new_handler.

    使用如下:
    //为Allocate类设置内存分配出错处理函数
    Allocate::set_new_handler(NoMemory);
    //new
    Allocate *= new Allocate;
    delete p;

    重载operator new和operator delete的注意事项
    new:
    1、如果成功返回指向内存的指针,如果失败抛出std::bad_alloc异常。
    2、c++标准要求,在请求0字节分配时也要返回合法指针。
    3、operator new中存在一个无限循环,以下几种情况可以跳出循环:
                分配内存成功,return指向内存的指针;
                外界通过set_new_handler(NULL)卸载了new_handler,导致抛出std::bad_alloc异常。
         否则就会一直循环,执行new_handler。
    4、注意父类的operator new可能会被子类调用,子类的size可能会比父类大。

    实现伪代码:

    void * operator new(size_t size)
    {                                       
      
    if (size == 0
      
    {    
        
    // 处理0字节请求时,把它当作1个字节请求来处理
        size = 1;                           
      }
                                         
      
    while (1
      
    {
        分配size字节内存;

        
    if (分配成功)
          
    return (指向内存的指针);

        
    // 分配不成功,找出当前出错处理函数
        new_handler globalhandler = set_new_handler(0);
        set_new_handler(globalhandler);

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

    }


    delete:
    为了保证删除空指针是安全的,需要判断传入指针是否为空。


    重载operator的规则:
    1、operator new的返回值是void*,第一个参数是size_t,格式:

    void* operator new(size_t, para2, para3)

    调用时格式:

    void *= new(para2, para3)TYPE;

    2、operator delete的返回值为void,第一个参数是void*,格式:

    void operator delete(void*, para2, para3)

    调用时格式:

    delete p                            //调用void operator delete(void*)
    operator delete(p, para2, para3)    //调用void operator delete(void*, para2, para3)

    全局的重载

    void* operator new(size_t)            {cout<<"new(size_t)"<<endl; return NULL;}
    void* operator new(size_t, int)        {cout<<"new(size_t, int)"<<endl; return NULL;}
    //无法重载全局的placement new,报错
    //void* operator new(size_t, void*)    {cout<<"new(size_t, void*)"<<endl; return NULL;}

    void* operator new[] (size_t)        {cout<<"new[] (size_t)"<<endl; return NULL;}
    void* operator new[] (size_t, int)    {cout<<"new[] (size_t, int)"<<endl; return NULL;}
    //无法重载全局的placement new,报错
    //void* operator new[] (size_t, void*)    {cout<<"new(size_t, void*)"<<endl; return NULL;}

    //operator delete
    void operator delete(void*)            {cout<<"delete(void*)"<<endl;}
    void operator delete(void*, size_t)    {cout<<"delete(void*, size_t)"<<endl;}
    void operator delete[](void*)        {cout<<"delete[](void*)"<<endl;}
    void operator delete[](void*, size_t)    {cout<<"delete(void*, size_t)"<<endl;}

    调用:

        int *= new int;            //call operator new(size_t)
        int *p1 = new(2)int;        //call operator new(size_t, int)
        delete p;                    //call operator delete(void*)    

        
    int *p2 = new int[3];        //call operator new[] (size_t)
        int *p3 = new(3int[3];    //call operator new[] (size_t, int)
        delete[] p2;                //call delete[](void*)

    若没有重载operator new(size_t) 和operator delete(void*) ,则调用全局的。
    传说void operator delete(void*, size_t) 会在catch到异常时被调到。
    []格式同上。


    类中的重载

    class Object
    {
    public:
        
    //operator new
        void* operator new(size_t)            {cout<<"new(size_t)"<<endl; return NULL;}
        
    void* operator new(size_t, void*)    {cout<<"new(size_t, void*)"<<endl; return NULL;}

        
    //operator delete
        void operator delete(void*)            {cout<<"delete(void*)"<<endl;}
        
    void operator delete(void*, size_t)    {cout<<"delete(void*, size_t)"<<endl;}
    }
    ;

    调用:
        Object *= new Object;            //call operator new(size_t)
        Object *p1 = new(NULL) Object;    //call operator new(size_t, void*)
        delete p;                        //call delete(void*)

    若类中没有定义void operator delete(void*),则delete p调用void operator delete(void*, size_t)   
    若类中没有定义void* operator new(size_t) ,则 Object *= new Object 报错,重载的非单参数的operator new隐藏了全局的单参数的operator new。
    []格式同上。

    所以类中最好重载一下标准形式的operator new:
    class Overload
    {
    public:
        
    //重载operator new
        static void* operator new(size_t size, int i, char c){return NULL;}
        
    static void* operator new(size_t size){return ::operator new(size);}
    }
    ;
  • 相关阅读:
    黑马day16 jquery案例演示
    duilib各种布局的作用,相对布局与绝对布局的的意义与使用方法
    Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: “object”未包括“get_Range”的定义
    Android App 内存泄露之调试工具(1)
    手动安装huson插件的做法
    Linux管理日记(二)
    小强的HTML5移动开发之路(9)——坦克大战游戏3
    TextView中实现跑马灯的最简单方法
    Android中使用achartengine生成图表
    Android菜鸟的成长笔记(6)——剖析源码学自定义主题Theme
  • 原文地址:https://www.cnblogs.com/BloodAndBone/p/1957783.html
Copyright © 2020-2023  润新知