• C++ 操作符new和delete


    参考资料:

    http://en.cppreference.com/w/cpp/memory/new/operator_new

    http://en.cppreference.com/w/cpp/memory/new/operator_delete

    http://www.wuzesheng.com/?p=840

    http://www.blogjava.net/bacoo/archive/2008/07/13/214612.html

    #include <cstdio>
    #include <cstdlib>
    
    void * operator new(size_t unSize)
    {
        printf("operator new called
    ");
        return malloc(unSize);
    }
    void * operator new[](size_t unSize)
    {
        printf("operator [] called
    ");
        return malloc(unSize);
    }
    
    void * operator new(size_t unSize, int nLine, const char * pFunc)
    {
        printf("operator new called, line: %d, func: %s
    ",
            nLine, pFunc);
        return malloc(unSize);
    }
    //注意:c++14才支持全局delete或delete【】有多个参数,参看参考资料2.下面两个delete不会覆盖全局的。
    void operator delete(void * pMem,size_t unSize)
    {
         printf("delete1: %u
    ", unSize);
        free(pMem);
    }
    void operator delete[](void * pMem, size_t unSize)
    {
              printf("delete[]: %u
    ", unSize);
              free(pMem);
     }
    
    class A
    {
    public:
        
        A(int a = 0) :
          _a(a)
          {   
              printf("constructor called
    ");
          }  
         virtual ~A()
          {
              printf("~A()
    ");
          }
          void * operator new(size_t unSize)
          {
              printf(" calledA
    ");
              return malloc(unSize);
              
          }
         //注意:但是支持自定义类型操作符new或delete重载支持size_t参数。即要删除对象的大小delete,要删除对象数组大小delete[].。
    void operator delete(void * pMem, size_t unSize) { printf("delete2: %u ", unSize); free(pMem); } void operator delete[](void * pMem, size_t unSize) { printf("delete[]: %u ", unSize); free(pMem); } private: int _a; }; class B: public A { public: //隐式的为静态函数。 void * operator new(size_t unSize, int nLine, const char * pFunc) { printf("operator new called, line: %d, fileB: %s ", nLine, pFunc); printf("operator new: %u ", unSize); //_b=0; return malloc(unSize); } ~B() { printf("~B() "); } int _b; int _bb; }; int main() { A * pA = new A(10); printf("####### "); A * pB = new (__LINE__, __FILE__) B(); printf("####### "); A * szA = new A[10]; B *szB = new B[10]; printf("####### "); delete pA; printf("####### "); delete pB; printf("####### "); delete [] szA; printf("####### "); delete [] szB; printf("####### ");
    //下面两个不是自定义类,没有类重载new.delete故只能调用全局的,本程序全局不支持size_t参数,故只能调用标准C++中的全局operate delete.故不会打印信息。
    char * pC = new char[10]; delete [] pC;
    char *pu = NULL;
    delete pu;
    }

    gcc下运行结果:

     calledA
    constructor called
    #######
    operator new called,
    operator new: 16
    constructor called
    #######
    operator [] called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    operator [] called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    constructor called
    #######
    ~A()
    delete2: 8
    #######
    ~B()
    ~A()
    delete2: 16
    #######
    ~A()
    ~A()
    ~A()
    ~A()
    ~A()
    ~A()
    ~A()
    ~A()
    ~A()
    ~A()
    delete[]: 84//注意84=4+8*10,数组分配的堆空间,第一个int空间放数组个数,接下来顺序放对象
    ####### ~B() ~A() ~B() ~A() ~B() ~A() ~B() ~A() ~B() ~A() ~B() ~A() ~B() ~A() ~B() ~A() ~B() ~A() ~B() ~A() delete[]: 164 ####### operator [] called //调用覆盖的全局函数operate new [],打印信息。
    //delete[]调用全局的。

     说明:1 在vs中类中delete[]的size_t是8和16.不同编译器结果不同。理论上应该是数组大小*类型字节。

             2 如果基类有virtual析构函数,则传给operator delete的大小讲个怒被删除指针所指对象的动态类型而变化,如果没有声明为virtual,那么通过基类指针删除指向派生类对象,大小为基类大小。

    总结:

    1 malloc只是C函数,内部应该是使用类似deepalloc等,主要功能是分配原始内存,返回void*类型,需要显示转换为对应对象 类型指针。没有调用对象构造函数。C中函数本来就没有类没有构造函数。

       free释放回收堆空间。

    2 C++中的new 和delete是操作符,A * pA = new A(10)分别调用下面两步:

    先调用void * operator new(size_t unSize) (调用顺序:那个有就调用那个:类中重载了就调用类的,然后全局重载,最后是C++源码中的全局函数)分配原始内存,未初始化的。里面可以调用malloc或者类似deapalloc来分配内存。

    在调用A的构造函数,用初始化参数初始化。

    delete pA;也分两步:

    先调用A析构函数;

    在调用void operator delete(void * pMem)(调用顺序同上面operator new),释放内存。可调用free实现或者其他实现。

    3 operator new,operator delete隐式静态函数,写不写static都是静态的。

    为什么必须是静态的呢?因为他们要么在构造对象前使用要么在析构后使用。属于类的函数,不是对象的函数。

    4 operator new中传入的大小是怎么获得的呢,我觉得类似于sizeof(类型名)

    关于sizeof不需要实例对象,我觉得类为实例化编译器不会给成员变量分配空间,但应该有个地方放的声明,标明变量类型等。

    还有,sizeof大小不包括静态成员变量,静态变量一般放在静态区,不属于对象。没有成员变量的类大小为1,有虚函数就要多4个字节(虚函数表指针)。

    最后小结一下,new 和delete都是内建的操作符,语言本身所固定了,无法重新定制。但它所调用的内存分配/释放的函数,即operator new和operator delete可以被重载

    ps:

    从汇编代码可看出:对单个堆对象调用delete和对堆对象数组调用delete[]可以发现,两种情况最主要的差别是在调用析构代理函数时传递的对象首地址,用delete析构单个对象是传进的堆空间首地址(也是堆对象首地址),而用delete[]析构对象数组时传递的是偏移堆空间首地址4byte处内存地址(即堆空间中第一个对象首地址,前四个字节是个int型,放的数组大小,即对象个数)。因此,在释放单个对象时调用delete[],或者释放对象数组时调用delete,都会造成错误,应该配对使用。

  • 相关阅读:
    JQuery hover鼠标变换
    装饰者模式
    principle04
    Method Injection
    观察者模式
    Java SPI
    Redis--学习01
    OO设计中5大原则
    knowledge
    策略模式
  • 原文地址:https://www.cnblogs.com/Yogurshine/p/3668249.html
Copyright © 2020-2023  润新知