zoukankan      html  css  js  c++  java
  • 重载new和delete

    当我们创建一个new表达式时,会发生两件事。首先使用operator new()分配内存,然后调用构造函数。在delete表达式里,调用了析构函数,然后使用operator delete()释放内存。我们无法控制构造函数与析构函数的调用,但是可以改变内存分配函数operator new()和operator delete().

    在使用系统内置的new和delete的内存分配系统是为了通用的目的而设计的,但是在特殊的情形下,它并不能满足需求。有时候我们为了改善程序的效率,我们会重载operator new和operator delete.   也许要创建和销毁一个特定的类的非常多的对象以至于这个运算变成了速度的瓶颈。所以此时我们会选择重载new和delete.

    重载new和delete的理由还有防止内存碎片:分配大小不同的内存可能会在堆上产生很多碎片,以至于很快用完内存。虽然内存可能还有,但由于都是碎片,也就找不到足够大的内存满足需求。通过为特定类创建自己的内存分配器,可以确保这种情况不会发生。

    注意:我们虽然重载了new和delete,其实我们只是改变了内存分配和释放的部分,而内存构造函数和析构函数调用的部分没有改变。

    当operator new()找不到足够大的内存块来安排对象时,将对有一个特殊的函数被调用,这个函数是new-handler。new-handler的默认的动作是产生一个异常(exception)

     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<new>
     4 using namespace std;
     5 int count=0;
     6 
     7 void out_of_memory(){
     8    cerr<<"memory exhausted after"<<count<<"allocations!"<<endl;
     9      exit(1);
    10 
    11 }
    12 
    13 int main(){
    14    set_new_handler(out_of_memory);
    15    while(1){
    16        count++;
    17        new int[1000];
    18      }
    19 
    20 }

    上面的代码就是在内存耗尽时,new operator操作符调用new-handler函数out_of_memory。new-handler函数必须没有参数,返回值必须为void。那么我们在重载operator new时,也可改变用完内存时的行为,一种方法即使通过new-handler函数实现。

    重载new和delete与重载别的运算符一样,可以通过全局函数重载,也可以通过对特定的类的成员函数重载。当然通过全局函数重载new和delete是非常极端的做法,不建议这样做,虽然语法上是允许的。因为通过全局函数重载new和delete,那么编译器默认的版本就不能再使用了。

     重载new和delete语法,首先重载的new必须有一个size_t参数,这个参数是编译器产生并传递给我们,它是要分配内存的对象的长度。必须返回一个执行那个等于或者大于这个长度的对象指针,如果没有找到存储单元,则返回一个0.如果真没有找到存储单元,不能仅仅返回0,也许还应该做一些诸如调用new-handler或者产生一个void*的异常信息。 重载的new operator()要返回一个void*指针。operator delete()的参数也是一个void*指针,参数之所以是一个void*指针,是因为它是在调用析构函数后得到的指针,析构函数从存储单元里移除对象。opreator delete的返回类型是void。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 using namespace std;
     4 
     5 void* operator new(size_t sz){//重载的new
     6     printf("operator new:  %d
    ",sz);
     7     void* m= malloc(sz);
     8     if (!m)
     9         puts("out of memory");
    10     return m;
    11 }
    12 
    13 void operator delete(void* m){//重载的delete
    14     puts("operaor delete");
    15     free(m);
    16 }
    17 
    18 class S{
    19     int i[100];
    20 public:
    21     S(){ puts("S::S()"); }
    22     ~S(){ puts("S::~S()"); }
    23 
    24 };
    25 
    26 int main(){
    27     puts("creating & destorying an int");
    28     int* p = new int(42);
    29     delete p;
    30     puts("creating & destorying an s");
    31     S* s = new S;
    32     delete s;
    33     puts("creating & destorying an S[3]");
    34     S* sa = new S[3];
    35     delete[] sa;
    36     return 0;
    37 }

  • 相关阅读:
    DNS bind9安装
    DHCP服务器
    RAID
    LVM
    box-pack
    display:flex和display:box布局浏览器兼容性分析
    Flex布局
    几种常见的浏览器以及内核
    display 垂直居中
    font-family 定义的最后为什么要加一句sans-serif
  • 原文地址:https://www.cnblogs.com/cplinux/p/5679564.html
Copyright © 2011-2022 走看看