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的调用得到调用。

原文地址:https://www.cnblogs.com/SKY-ZL/p/8413321.html