【C++ Primer | 19】控制内存分配
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
- 特殊的工具和技術
總結
以上是生活随笔為你收集整理的【C++ Primer | 19】控制内存分配的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 107. 二叉树的层次遍历 II
- 下一篇: 3D投影仪市场现状和未来发展趋势