重載new和delete運算符


內存管理運算符 new、new[]、delete 和 delete[] 也可以進行重載,其重載形式既可以是類的成員函數,也可以是全局函數。一般情況下,內建的內存管理運算符就夠用了,只有在需要自己管理內存時才會重載。

以成員函數的形式重載 new 運算符:

void * className::operator new( size_t size ){
    //TODO:
}

 

以全局函數的形式重載 new 運算符:

void * operator new( size_t size ){
    //TODO:
}

 

兩種重載形式的返回值相同,都是void *類型,並且都有一個參數,為size_t類型

在重載 new 或 new[] 時,無論是作為成員函數還是作為全局函數,它的第一個參數必須是 size_t 類型size_t 表示的是要分配空間的大小對於 new[] 的重載函數而言,size_t 則表示所需要分配的所有空間的總和。

重載的new必須有一個size_t參數。這個參數由編譯器產生並傳遞給我們它是要分配內存的對象的長度。必須返回一個指向等於這個長度(或者大於這個長度)的對象的指針。如果沒有找到存儲單元(在這種情況下,構造函數不被調用),則返回一個0。然后如果找不到存儲單元,不能僅僅返回0,我們還應該調用new-handler或產生一個異常信息之類的事,告訴這里出現了問題。

我們首先需要明白的一點就是:operator new()的返回值是一個void*,而不是指向任何特定類型的指針。所做的是分配內存,而不是完成一個對象建立--直到構造函數調用了才完成對象的創建,它是編譯器確保做的動作,不在我們的控制范圍之內了,所以我們就沒有必要考慮。

size_t 在頭文件 <cstdio> 中被定義為typedef unsigned int size_t;,也就是無符號整型。

當然,重載函數也可以有其他參數,但都必須有默認值,並且第一個參數的類型必須是 size_t。

同樣的,delete 運算符也有兩種重載形式。以類的成員函數的形式進行重載:

void className::operator delete( void *ptr){
    //TODO:
}

 

以全局函數的形式進行重載:

void operator delete( void *ptr){
    //TODO:
}

 

兩種重載形式的返回值都是 void 類型,並且都必須有一個 void 類型的指針作為參數,該指針指向需要釋放的內存空間

當我們以類的成員函數的形式重載了new 和 delete 操作符,其使用方法如下:

C * c = new C; //分配內存空間
//TODO:
delete c; //釋放內存空間

 

如果類中沒有定義 new 和 delete 的重載函數,那么會自動調用內建的 new 和 delete 運算符。

 

重載全局new和delete

#include <QCoreApplication>

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 0x7fffffff
using namespace std;

void* operator new(size_t sz)
{
    printf("operator new: %d Bytes\n",sz);
    void* m = malloc(sz);
    if (!m) puts("out of memory");
    return m;
}

void* operator new [](size_t sz)
{
    printf("operator new: %d Bytes\n",sz);
    void* m = malloc(sz);
    if (!m) puts("out of memory");
    return m;
}

void operator delete(void* m)
{
    puts("operator delete");
    free(m);
}

void operator delete[](void* m)
{
    puts("operator delete");
    free(m);
}

class S
{
public:
    S() {puts("S::S()"); }
    ~S() {puts("S::~S()"); }
private:
    int an[1000];
};


void func()
{

    puts("creating & destroying an int");
    int* q = new int(23);
    delete q;
    puts("creating & destroying an int[]");
    int* p = new int[10]();
    delete []p;
    puts("creating & destroying an s");
    S* s = new S;
    delete s;
    puts("creating & destroying S[3]");
    S* sa = new S[3];
    delete []sa;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    func();

    return a.exec();
}

 

輸出:

creating & destroying an int
operator new: 4 Bytes
operator delete
creating & destroying an int[]
operator new: 40 Bytes
operator delete
creating & destroying an s
operator new: 4000 Bytes
S::S()
S::~S()
operator delete
creating & destroying S[3]
operator new: 12004 Bytes
S::S()
S::S()
S::S()
S::~S()
S::~S()
S::~S()
operator delete

 

對於一個類重載new和delete

為一個類重載new和delete的時候,盡管不必顯式的使用static,但是實際上仍是在創建static成員函數。它的語法也和重載任何其它運算符一樣。當編譯器看到使用new創建自己定義的類的對象時,它選擇成員版本的operator new()而不是全局版本的new()。但是全局版本的new和delete仍為所有其他類型對象使用(除非它們也有自己的new和delete)。這個和全局變量、局部變量的意思是一樣的。

 

#include<iostream>
#include<cstddef>
#include<fstream>
#include<new>
using namespace std;
ofstream out("Framis.out");

class Framis
{
public:
    enum{psize = 100 };
    Framis() {out<< "Framis()" <<endl; }
    ~Framis() {out<< "~Framis() ... " <<endl; }
    void* operator new(size_t) throw (bad_alloc);
    void operator delete(void*);
private:
    enum{sz = 10 };
    char c[sz];
    static unsigned char pool[];
    static bool alloc_map[];
};
unsigned char Framis::pool[psize*sizeof(Framis)];
bool Framis::alloc_map[psize]={false};

void* Framis::operator new(size_t sz) throw(bad_alloc)
{
    for (int i=0; i<psize; ++i) {
        if (!alloc_map[i]) {
            out<< "using block " << i << " ... ";
            alloc_map[i]=true;
            return pool+(i*sizeof(Framis));
        }
    }
    out<< "out of memory" <<endl;
    throw bad_alloc();
}

void Framis::operator delete(void* m)
{
    if (!m) return;
    unsigned long block = (unsigned long)m-(unsigned long)pool;
    block /= sizeof(Framis);
    out<< "freeing block " << block <<endl;
    alloc_map[block]=false;
}

int main()
{
cout << sizeof(Framis) << endl; Framis
* f[Framis::psize]; try { for (int i=0; i<Framis::psize; i++) { f[i]=new Framis; // new 的時候先跑進 new 重載函數中,再調用構造函數 } new Framis; } catch(bad_alloc) { cerr<< "Out of memory!" <<endl; } delete f[10]; f[10]=0; Framis* X=new Framis; delete X;// delete 的時候先調用析構函數,再跑進delete重載函數中 for (int j=0; j<Framis::psize; j++) { delete f[j]; } return 0; }

 

10 // sizeof Framis
using block 0 ... Framis()
using block 1 ... Framis()
using block 2 ... Framis()
using block 3 ... Framis()
using block 4 ... Framis()
using block 5 ... Framis()
using block 6 ... Framis()
using block 7 ... Framis()
using block 8 ... Framis()
using block 9 ... Framis()
using block 10 ... Framis()
using block 11 ... Framis()
using block 12 ... Framis()
using block 13 ... Framis()
using block 14 ... Framis()
using block 15 ... Framis()
using block 16 ... Framis()
using block 17 ... Framis()
using block 18 ... Framis()
using block 19 ... Framis()
using block 20 ... Framis()
using block 21 ... Framis()
using block 22 ... Framis()
using block 23 ... Framis()
using block 24 ... Framis()
using block 25 ... Framis()
using block 26 ... Framis()
using block 27 ... Framis()
using block 28 ... Framis()
using block 29 ... Framis()
using block 30 ... Framis()
using block 31 ... Framis()
using block 32 ... Framis()
using block 33 ... Framis()
using block 34 ... Framis()
using block 35 ... Framis()
using block 36 ... Framis()
using block 37 ... Framis()
using block 38 ... Framis()
using block 39 ... Framis()
using block 40 ... Framis()
using block 41 ... Framis()
using block 42 ... Framis()
using block 43 ... Framis()
using block 44 ... Framis()
using block 45 ... Framis()
using block 46 ... Framis()
using block 47 ... Framis()
using block 48 ... Framis()
using block 49 ... Framis()
using block 50 ... Framis()
using block 51 ... Framis()
using block 52 ... Framis()
using block 53 ... Framis()
using block 54 ... Framis()
using block 55 ... Framis()
using block 56 ... Framis()
using block 57 ... Framis()
using block 58 ... Framis()
using block 59 ... Framis()
using block 60 ... Framis()
using block 61 ... Framis()
using block 62 ... Framis()
using block 63 ... Framis()
using block 64 ... Framis()
using block 65 ... Framis()
using block 66 ... Framis()
using block 67 ... Framis()
using block 68 ... Framis()
using block 69 ... Framis()
using block 70 ... Framis()
using block 71 ... Framis()
using block 72 ... Framis()
using block 73 ... Framis()
using block 74 ... Framis()
using block 75 ... Framis()
using block 76 ... Framis()
using block 77 ... Framis()
using block 78 ... Framis()
using block 79 ... Framis()
using block 80 ... Framis()
using block 81 ... Framis()
using block 82 ... Framis()
using block 83 ... Framis()
using block 84 ... Framis()
using block 85 ... Framis()
using block 86 ... Framis()
using block 87 ... Framis()
using block 88 ... Framis()
using block 89 ... Framis()
using block 90 ... Framis()
using block 91 ... Framis()
using block 92 ... Framis()
using block 93 ... Framis()
using block 94 ... Framis()
using block 95 ... Framis()
using block 96 ... Framis()
using block 97 ... Framis()
using block 98 ... Framis()
using block 99 ... Framis()
out of memory
Out of memory!
~Framis() ...
freeing block 10
using block 10 ... Framis()
~Framis() ...
freeing block 10
~Framis() ...
freeing block 0
~Framis() ...
freeing block 1
~Framis() ...
freeing block 2
~Framis() ...
freeing block 3
~Framis() ...
freeing block 4
~Framis() ...
freeing block 5
~Framis() ...
freeing block 6
~Framis() ...
freeing block 7
~Framis() ...
freeing block 8
~Framis() ...
freeing block 9
~Framis() ...
freeing block 11
~Framis() ...
freeing block 12
~Framis() ...
freeing block 13
~Framis() ...
freeing block 14
~Framis() ...
freeing block 15
~Framis() ...
freeing block 16
~Framis() ...
freeing block 17
~Framis() ...
freeing block 18
~Framis() ...
freeing block 19
~Framis() ...
freeing block 20
~Framis() ...
freeing block 21
~Framis() ...
freeing block 22
~Framis() ...
freeing block 23
~Framis() ...
freeing block 24
~Framis() ...
freeing block 25
~Framis() ...
freeing block 26
~Framis() ...
freeing block 27
~Framis() ...
freeing block 28
~Framis() ...
freeing block 29
~Framis() ...
freeing block 30
~Framis() ...
freeing block 31
~Framis() ...
freeing block 32
~Framis() ...
freeing block 33
~Framis() ...
freeing block 34
~Framis() ...
freeing block 35
~Framis() ...
freeing block 36
~Framis() ...
freeing block 37
~Framis() ...
freeing block 38
~Framis() ...
freeing block 39
~Framis() ...
freeing block 40
~Framis() ...
freeing block 41
~Framis() ...
freeing block 42
~Framis() ...
freeing block 43
~Framis() ...
freeing block 44
~Framis() ...
freeing block 45
~Framis() ...
freeing block 46
~Framis() ...
freeing block 47
~Framis() ...
freeing block 48
~Framis() ...
freeing block 49
~Framis() ...
freeing block 50
~Framis() ...
freeing block 51
~Framis() ...
freeing block 52
~Framis() ...
freeing block 53
~Framis() ...
freeing block 54
~Framis() ...
freeing block 55
~Framis() ...
freeing block 56
~Framis() ...
freeing block 57
~Framis() ...
freeing block 58
~Framis() ...
freeing block 59
~Framis() ...
freeing block 60
~Framis() ...
freeing block 61
~Framis() ...
freeing block 62
~Framis() ...
freeing block 63
~Framis() ...
freeing block 64
~Framis() ...
freeing block 65
~Framis() ...
freeing block 66
~Framis() ...
freeing block 67
~Framis() ...
freeing block 68
~Framis() ...
freeing block 69
~Framis() ...
freeing block 70
~Framis() ...
freeing block 71
~Framis() ...
freeing block 72
~Framis() ...
freeing block 73
~Framis() ...
freeing block 74
~Framis() ...
freeing block 75
~Framis() ...
freeing block 76
~Framis() ...
freeing block 77
~Framis() ...
freeing block 78
~Framis() ...
freeing block 79
~Framis() ...
freeing block 80
~Framis() ...
freeing block 81
~Framis() ...
freeing block 82
~Framis() ...
freeing block 83
~Framis() ...
freeing block 84
~Framis() ...
freeing block 85
~Framis() ...
freeing block 86
~Framis() ...
freeing block 87
~Framis() ...
freeing block 88
~Framis() ...
freeing block 89
~Framis() ...
freeing block 90
~Framis() ...
freeing block 91
~Framis() ...
freeing block 92
~Framis() ...
freeing block 93
~Framis() ...
freeing block 94
~Framis() ...
freeing block 95
~Framis() ...
freeing block 96
~Framis() ...
freeing block 97
~Framis() ...
freeing block 98
~Framis() ...
freeing block 99
輸出

 

為數組重載new和delete

上一段文字中我們講到如果為一個類重載operator new()和operator delete(),那么無論何時創建這個類的一個對象都將調用這些運算符。但是如果要創建這個類的一個對象數組的時候,全局operator new()就會被立即調用,用來為這個數組分配足夠的內存。對此,我們可以通過為這個類重載運算符的數組版本,即operator new[]和operator delete[],來控制對象數組的內存分配。

#include<iostream>
#include<fstream>
#include<new>
using namespace std;
ofstream trace("ArrayOperatorNew.out");

class Widget
{
public:
    Widget() {trace<< "*" <<endl; }
    ~Widget() {trace<< "~" <<endl; }
    void* operator new(size_t sz) {
        trace<< "Widget::new: " << sz << " byte" <<endl;
        return ::new char[sz];
    }
    void operator delete(void* p) {
        trace<< "Widget::delete" <<endl;
        ::delete []p;
    }
    void* operator new[](size_t sz) {
        trace<< "Widget::new[]: " << sz << " bytes" <<endl;
        return ::new char[sz];
    }
    void operator delete[](void* p) {
        trace<< "Widget::delete[]" <<endl;
        ::delete []p;
    }
private:
    enum{sz=10 };
    int an[sz];
};

int main()
{
    trace<< "new Widget" <<endl;
    Widget* w=new Widget;
    trace<<endl<< "delete Widget" <<endl;
    delete w;
    trace<<endl<< "new Widget[25]" <<endl;
    Widget* wa=new Widget[25];
    trace<<endl<< "delete []Widget" <<endl;
    delete []wa;
    return 0;
}

 

new Widget
Widget::new: 40 byte
*

delete Widget
~
Widget::delete

new Widget[25]
Widget::new[]: 1004 bytes
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

delete []Widget
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
Widget::delete[]
輸出

 

 

C++空類的大小是1

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM