• Geekband C++面向对象高级程序设计-第五周课程3


    #new与delete回顾

      new:先分配memory内存,在调用ctor构造函数。

      #转换方式

    • Complex类
    class Complex{
        public:
            Complex(int _m_real,int _m_imag):
                m_real(_m_real),m_imag(_m_imag){ }
        private:
            double m_real;
            double m_real;
    };
    • 创建类对象

    Complex* pc=new Complex(1,2);

    • 编译器转换
    void* mem=operator new(sizeof(Complex));
    pc=static_cast<Complex*>(mem);
    pc->Complex::Complex(1,2);
    • 图模型

       delete:先调用dtor,在释放memory

    • 调用析构函数
    delete pc;
    • 编译器转换为
    Complex::~Complex(pc);
    operator delete(pc);
    • 图模型

    • #补充:表达式行为不可改变,即不能重载也即 new 所分解出1,2,3 delete 所分解出1,2的事实不可改变。但是分解后的函数可以重载。
    • #补充:析构函数并不释放内存,释放内存为独立操作。

    #重载(全局)::operator new new[] 或者 重载::operator delete delete[]

    • 全局函数
    void* myAlloc(size_t size){
        return malloc(size);
    }
    
    void myFree(void* ptr){
        return free(ptr);
    }
    • 上述四个函数重载实例
    inline void* operator new(size_t size){
        cout << "global new() " <<endl;
        return myAlloc(size);
    }
    
    inline void* operator new[](size_t size){
        cout << "global new[]() " <<endl;
        return myAlloc(size);
    }
    
    inline void operator delete(void* ptr){
        cout << "global delete() " <<endl;
        myFree(ptr);
    }
    
    inline void operator delete[](void* ptr){
        cout << "global delete[]() " <<endl;
        myFree(ptr);
    }
    • #补充:new需要一个参数,开辟内存空间的大小。delete需要传递指向需要销毁内存的指针,以便销毁内存。

    #重载member operator new/delete

    • #提示:对类中的成员做重载。
    • Foo类
    class Foo{
        public:
            void* operator new(size_t);
            void  operator delete(void*,size_t);
    }; 
    • 构造函数与析构函数调用
    Foo* p = new Foo;
    delete p;
    • 编译器转换方式
    try{
        void* mem = operator new(sizeof(Foo));
        p = static_cast<Foo*>(mem);
        p->Foo::Foo();
    }
    p->~Foo();
    operator delete(p);
    • 图模型

    #重载member operator new[]/delete[]

      #需要注意new与delete的语法规则,与重载函数的语法规则。同时注意内部函数写法。

    • Foo类
    class Foo{
        public:
            void* operator new[](size_t);
            void  operator delete[](void*,size_t);
    };
    • 构造函数析构函数调用
    Foo* p = new Foo[N];
    delete[] p;
    • 编译器转换方式
    try{
        void* mem = operator new(sizeof(Foo)*n+4);
        p->Foo::Foo();
    }
    
    p->~Foo();
    operator delete(p);
    • 图模型

     #示例程序

    • Foo类
    class Foo{
        public:
            int _id;
            long _data;
            string _str;
        public:
            Foo():_id(0){
                cout << "default ctor.this= " << this <<endl;
            }
            Foo(int i):_id(i){
                cout << "ctor.this=" << this << "id=" <<_id <<endl; 
            }
            ~Foo(){
                cout << "dtor.this=" << this << "id=" << _id <<endl;
            }
            static void* operator new(size_t size);
            static void  operator delete(void* pdead,size_t size);
            static void* operator new[](size_t size);
            static void  operator delete[](void* pdead,size_t size);
    }; 
    • 类成员函数
    void* Foo::operator new(size_t size){
        Foo* p = (Foo*)malloc(size);
        cout<<"new"<<endl;
        return p;
    }
    
    void Foo::operator delete(void* pdead,size_t size){
        cout << "delete" <<endl;
        free(pdead);
    }
    
    void* Foo::operator new[](size_t size){
        Foo* p = (Foo*)malloc(size);
        cout << "new[]" <<endl;
        return p;
    }
    
    void Foo::operator delete[](void* pdead,size_t size){
        cout << "delete[]" <<endl;
        free(pdead);
    }
    • 调用构造函数与析构函数
    int main(){
        Foo* pf = new Foo;
        delete pf;
        
        Foo* pf1 = ::new Foo;
        ::delete pf1;
        return 0;
    }

      #补充:强制全局new与delete可用::new ::new[] ::delete ::delete[]。同样若没有全局函数大可不必这样写,其直接调用全局函数。

    #内存结构探索

    • 代码示例
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Foo{
        public:
            int _id;
            long _data;
            string _str;
        public:
            Foo():_id(0){
                cout << "ctor.this          = " << this<<endl;
            }
            ~Foo(){
                cout << "dtor.this          = " << this<<endl;
            }
            static void* operator new(size_t size);
            static void  operator delete(void* pdead,size_t size);
            static void* operator new[](size_t size);
            static void  operator delete[](void* pdead,size_t size);
    }; 
    
    void* Foo::operator new(size_t size){
        Foo* p = (Foo*)malloc(size);
        cout <<"Foo::operator new()     "<<"size  ="<<size<<endl;
        return p;
    }
    
    void Foo::operator delete(void* pdead,size_t size){
        cout << "Foo::operator delete()  "<<"size  ="<<size<<endl;
        free(pdead);
    }
    
    void* Foo::operator new[](size_t size){
        Foo* p = (Foo*)malloc(size);
        cout << "Foo::operator new[]     "<<"size  ="<<size<<endl;
        return p;
    }
    
    void Foo::operator delete[](void* pdead,size_t size){
        cout << "Foo::operator delete[]  "<<"size  ="<<size<<endl;
        free(pdead);
    }
    
    int main(){
        Foo* pf = new Foo;
        delete pf;
        
        Foo* pf1 = new Foo[5];
        delete[] pf1;
    //    Foo* pf1 = ::new Foo;
    //    ::delete pf1;
        return 0;
    }
    View Code
    • 运行结果

      #补充说明

      由运行结果可以分析得出,构造函数的内存分配由上至下,析构函数的内存释放由下至上。并且,对于对象数组其内存会多分配8个字节,用来存放对象数组相关信息。

    #重载new() delete()

      class member operator new() 可以重载出多个版本,但是其必须符合重载要求每个声明都要有独特的参数列,其中第一个参数必须是size_t,其余参数以new所指定的placement arguments为初值。出现new()小括号内的记为placement arguments。

    • 示例
    Foo* pf = new(300,'c')Foo;

      同时可以重载class member operator delete()但是并非必须。重载的delete被调用时当且仅当new所调用的ctor构造函数抛出异常exception。之所以被这样调用,主要是用来归还未能完全创建成功的对象object所占用的memory。

    • 测试实例   
    #include <iostream>
    
    using namespace std;
    
    class Foo{
        public:
            Foo(){
                cout<<"Foo::Foo()"<<endl;
            }
            Foo(int){
                cout<<"Foo::Foo(int)"<<endl;
            } 
            //operator new() 重载
            void* operator new(size_t size){
                return malloc(size);
            } 
            //标准库提供placement new() 的重载
            void* operator new(size_t size,void* start){
                return start; 
            } 
            //新的placement new
            void* operator new(size_t size,long extra){
                return malloc(size+extra);
            } 
            //新的placement new
            void* operator new(size_t size,long extra,char init) {
                return malloc(size+extra);
            }
            //故意写错 
        //    void* operator new(long extra,char init){
        //        return malloc(extra);
        //    }
            //一般operator delete()的重载
            void operator delete(void*,size_t){
                cout<<"operator delete(void*,size_t"<<endl;
            } 
            //对应2
            void operator delete(void*,void*){
                cout<<"operator delete(void*,void*)"<<endl;
            } 
            //对应3
            void operator delete(void*,long){
                cout << "operator delete(void*,long)"<<endl;
            } 
            //对应4
            void operator delete(void*,long,char){
                cout<<"opertor delete(void*,long,char)"<<endl;
            } 
    };
    
    int main(){
        Foo start;
        Foo* p1 = new Foo;
        Foo* p2 = new(&start)Foo;
        Foo* p3 = new(100)Foo;
        Foo* p4 = new(100,'a')Foo;
        Foo* p5 = new(100)Foo(1);
        Foo* p6 = new(100,'a')Foo(1);
        Foo* p7 = new(&start)Foo(1);
        Foo* p8 = new Foo(1);
        return 0; 
    }
    View Code

      #补充:测试代码写错部分在dev C++ 中无法编译通过。侯捷老师在不同版本编译器中,编译通过后可运行跳转到自定义delete中,而另一款编译器编译通过后,并没有跳转自定义delete。

         另外即使不写出一一对应的delete也不会有任何报错,编译器编译通过会报warning,显示出自动放弃检查警告。

     #Basic_String

    • basic_string 使用new(extra)扩充申请量
    class basic_string{
        private:
            void release() {
                if(--ref==0){
                    delete this;
                }
            }
            inline static void* operator new(size_t,size_t);
            inline static void  operator delete(void*);
            inline static Rep*  create(size_t);
    };
    
    basic_string<charT,traits,Allocator>::Rep::
    create(size_t extra){
        extra = frob_size(extra+1);
        Rep* p = new(extra)Rep;
        return p;
    }
    
    template<class charT,class traits,class Allocator>
    inline void* basic_string<charT,traits,Allocator>::Rep::
    operator new(size_t,size_t extra){
        return Allocator::allocate(s+extra*sizeof(charT));
    }
    View Code

      #补充说明:此为侯捷老师添加标准库代码的例子,例子并不完整,摘抄其中一部分代码,new 调用时经过成员函数create的调用得到调用。

  • 相关阅读:
    特性标签的灵活使用
    算法实例题
    网络抓包工具
    vs2010
    .NET Remoting vs Web Service
    电子商务网站设计学习
    EXCEL导出
    C# 16进制与字符串、字节数组之间的转换
    DES加密
    DataGridView生成CSV,XML 和 EXCEL文件
  • 原文地址:https://www.cnblogs.com/SKY-ZL/p/8413321.html
Copyright © 2020-2023  润新知