重載new,delete運算符
new,delete在c++中也被歸為運算符,所以可以重載它們。
new的行為:
-
先開辟內存空間
-
再調用類的構造函數
開辟內存空間的部分,可以被重載。
delete的行為:
-
先調用類的析構函數
-
再釋放內存空間
釋放內存空間的部分,可以被重載。
為什么要要重載它們?
有時需要實現內存池的時候需要重載它們。頻繁的new和delete對象,會造成內存碎片,內存不足等問題,影響程序的正常執行,所以一次開辟一個適當大的空間,每次需要對象的時候,不再需要去開辟內存空間,只需要調用構造函數(使用placement new)即可。
new,delete的重載函數,可以是全局函數,也可以是類內部的公有重載函數;當既有全局的重載函數,也有類內部的公有重載函數時,實際調用的是類內部的公有重載函數。
new,delete可以有多種重載方式,但是,new函數的第一個參數一定要是size_t類型
重載方式1,new單個對象
void* operator new(size_t sz){
void* o = malloc(sz);
return o;
}
void operator delete(void *o){
free(o);
}
重載方式2,new對象的數組
void* operator new[](size_t sz){
void* o = malloc(sz);
return o;
}
void operator delete[](void *o){
free(o);
}
重載方式3,不開辟空間,只是調用給定對象(用地址識別)的構造方法,也叫placement new
//第一個參數size_t即使不使用,也必須有
void* operator new(size_t sz, String* s, int pos){
return s + pos;
}
小例子:
#include <iostream>
#include <string.h>
using namespace std;
class String{
public:
String(const char* str = ""){
cout << "Create" << endl;
if(NULL == str){
data = new char[1];
data[0] = '\0';
}
else{
data = new char[strlen(str) + 1];
strcpy(data, str);
}
}
~String(){
cout << "Free" << endl;
delete []data;
data = NULL;
}
private:
char* data = NULL;
};
//重載方式1
void* operator new(size_t sz){
cout << "in operator new" << endl;
void* o = malloc(sz);
return o;
}
void operator delete(void *o){
cout << "in operator delete" << endl;
free(o);
}
//重載方式2
void* operator new[](size_t sz){
cout << "in operator new[]" << endl;
void* o = malloc(sz);
return o;
}
void operator delete[](void *o){
cout << "in operator delete[]" << endl;
free(o);
}
//重載方式3
//第一個參數size_t即使不適用,也必須有
void* operator new(size_t sz, String* s, int pos){
return s + pos;
}
int main(){
String *s = new String("abc");
delete s;
String *sr = new String[3];
delete []sr;
//開辟內存池,但是還沒有調用過池里對象的構造方法
String *ar = (String*)operator new(sizeof(String) * 2);
//調用池里第一個對象的構造方法,不再開辟空間
new(ar, 0)String("first0");
//調用池里第二個對象的構造方法 ,不再開辟空間
new(ar, 1)String("first1");
//調用池里第一個對象的析構方法,注意不會釋放到內存
(&ar[0])->~String();
//調用池里第二個對象的析構方法,注意不會釋放到內存
(&ar[1])->~String();
//下面語句執行前,內存池里的對象可以反復利用
operator delete(ar);
}