1. 測試代碼:?
#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;if (void* ptr = malloc(size)) return ptr;elsethrow bad_alloc();
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}int main()
{int* ptr = new int(10);delete ptr;cout << endl << "------------" << endl << endl;ptr = new(20) int(10);delete ptr;return 0;
}
輸出結果:
分析:
從上面的結果可以看出,new int(10);直接先調用 operator new(size_t size); 由于int沒有構造函數,在那塊內存上調用int的構造函數; 在delete ptr; 的時間直接調用 operator delete(void * ptr);這個函數
當
new(20) int(10);
的時候,則調用重載版本的 operator new(size_t size, int flag); 而該函數有調用了 operator new(size_t size); 函數,釋放的時候delete ptr;還是直接只調用operator delete(void * ptr);(注:這里初步提出為啥不調用operator delete(void * ptr, int flag); 這個函數來釋放ptr ???因為它的用途不在這,而在于下面將要講的。
?
2. 測試代碼:
#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;void* ptr = malloc(size);return ptr;
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}class Base
{
public:Base(){cout << "Base construct" << endl;throw 2;}~Base(){cout << "Base destructor" << endl;}//類中定制的operator new會覆蓋全局的函數,但可以通過簡單的調用全局的函數來實現調用static void* operator new(size_t size){cout << "operator new of Base" << endl;return ::operator new(size); //調用全局的operator new}static void* operator new(size_t size, int flag){cout << "Override operator new of Base: " << flag << endl;return operator new(size);}static void operator delete(void* ptr){cout << "Operator delete of Base" << endl;::operator delete(ptr);}static void operator delete(void* ptr, int flag){cout << "Override operator delete of Base: " << flag << endl;operator delete(ptr);}int x;int y;
};
int main()
{try{Base* bptr = new(20) Base;}catch (...){cout << "catch a exception" << endl;}return 0;
}
輸出結果:
?
2. 若是不給Base類重載?static void operator delete(void * ptr, int flag);
這個函數,結果則如下圖:
#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;void* ptr = malloc(size);return ptr;
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}class Base
{
public:Base(){cout << "Base construct" << endl;throw 2;}~Base(){cout << "Base destructor" << endl;}//類中定制的operator new會覆蓋全局的函數,但可以通過簡單的調用全局的函數來實現調用static void* operator new(size_t size){cout << "operator new of Base" << endl;return ::operator new(size); //調用全局的operator new}static void* operator new(size_t size, int flag){cout << "Override operator new of Base: " << flag << endl;return operator new(size);}static void operator delete(void* ptr){cout << "Operator delete of Base" << endl;::operator delete(ptr);}int x;int y;
};
int main()
{try{Base* bptr = new(20) Base;}catch (...){cout << "catch a exception" << endl;}return 0;
}
輸出結果:
?
?
二、定位new表達式
operator new和operator delete和alloctor類的allocate和deallocate很像,都是負責分配和釋放內存的函數,但是對于operator new分配的內存空間我們無法使用construct函數構造對象,我們應該使用new的定位new形式構造對象。
1. 測試代碼:
#include <iostream>
#include <new>
using namespace std;const int chunk = 16;
class Foo
{
public:int val() { return _val; }Foo() { _val = 0; }
private:int _val;
};//預分配內存,但沒有Foo對象
char* buf = new char[sizeof(Foo) * chunk];
int main(void)
{//在buf中創建一個Foo對象Foo* pb = new (buf) Foo;//檢查一個對象是否被放在buf中if (pb->val() == 0){cout << "new expressio worked!" << endl;}//到這里不能再使用pbdelete[] buf;return 0;
}
placement new的作用就是:創建對象但是不分配內存,而是在已有的內存塊上面創建對象。用于需要反復 創建并刪除的對象上,可以降低分配釋放內存的性能消耗。定位new表達式(placement new expression),允許程序員將對象創建在已經被分配好的內存中,new表的式的形式如下:
new (place_address) type
new (palce_address) type (initializer-list)
【Note】:?
- 當只傳入一個指針類型的實參時,定位new表達式構造對象但是不分配內存,這個指針沒有要求,甚至可能是一個不是一個指向動態內存的指針
- 調用析構函數會銷毀對象,但是不會釋放內存。
?
2. 測試代碼:
#include <iostream>
using namespace std;
char addr1[100];
int main()
{cout << "******定位new表達式演示***by David***" << endl;char addr2[100];char *addr3 = new char[100];cout << "addr1 = " << (void*)addr1 << endl;cout << "addr2 = " << (void*)addr2 << endl;cout << "addr3 = " << (void*)addr3 << endl;int *p = nullptr;p = new(addr1)int; 把內存分配到靜態區*p = 1;cout << (void*)p << " " << *p << endl;p = new(addr2)int; 把內存分配到棧區*p = 2;cout << (void*)p << " " << *p << endl;p = new(addr3)int; //把內存分配到堆區*p = 3;cout << (void*)p << " " << *p << endl;return 0;
}
輸出結果:
?
參考資料
- 定制自己的new和delete:operator new 和 operator delete
- 特殊的工具和技術