技術在於交流、溝通,本文爲博主原創文章轉載請註明出處並保持做品的完整性c++
首先,咱們先看一下C++應用程序,使用memory的途徑以下圖所示數組
C++應用程序中申請內存基於分配器的實現(std::allocator),而分配器基於C++primitives(new,new[]...),c++primitives基於C語言中的malloc/free..,固然越底層的函數效率越高.安全
那咱們會想,直接用最底層的實現多好,效率還高.但若是你直接調用底層的函數去實現功能,雖然你的效率提升了,但你的程序的可移植性就會相應的下降.函數
不能否認底層語言的實現,體現出必定的我的能力.但過多的篇幅去實現底層語言,會影響開發效率.工具
下面說一下C++三種申請內存的工具,而後介紹一下這三種工具的簡單使用測試
A.new operator, delete operator : 申請內存+構造函數this
B.new[], delete[] : 用於數組類的操做spa
C.placement new : 定點new翻譯
一 new operator, delete operator,code
分配內存的函數的對應關係以下圖,下面主要介紹一下下面這些函數的簡單使用
int main() { void* p1 = malloc(512); //512bytes free(p1); complex<int>* p2 = new complex<int>; //one object delete p2; void* p3 = ::operator new(512);// 512bytes ::operator delete(p3); //一下函數都是non-static,必定要經過object調用,分配7個int的內存 void* p4 = allocator<int>().allocate(7);//allocator<int>()建立臨時對象 allocator<int>().deallocate((int*)p4,7); return 0; }
咱們都知道 new = operator new + 構造函數,delete = 析構函數 + operator delete .若是以代碼的形式表現出來應該是這樣
好比咱們建立一個複數類,
Complex* pc = new Complex(1,2);
那麼編譯器會將上面的代碼翻譯成
try { void* mem = operator new(sizeof(Complex)); //allocate pc = static_cast<Complex*>(mem); //cast pc->Complex::Complex(1,2); //只有編譯器能夠直接調用構造函數 } catch (std::bad_alloc) { //申請內存失敗... }
釋放內存
delete pc;
編譯器翻譯爲
pc->~Complex();//先調用析構函數 operator delete(pc);// operator delete的實現基於free()
二 new[]和delete[]
new[],主要運用於數組的申請內存,
如class A 當咱們調用
A* p = new A[3];//那麼就會申請3個class A的內存並調用3次 class A的構造函數
當咱們調用 delete[]時
delete[] p; //就會調用3次析構函數 並釋放內存(3個class A的內存)
若是咱們釋放時沒有加[]
delete p;
它一樣會釋放3個class A的內存,可是以後調用其一個構造函數(若是其構造函數內有其餘釋放內存的操做,那麼咱們不加[]就會形成內存泄漏)
看一下測試代碼
class A { public: int id; A() : id(0) { cout << "default ctor.this=" << this << " id=" << id << endl; } A(int i): id(0) { cout << "ctor.this=" << this << " id=" << id << endl; } ~A() { cout << "dtor.this=" << this << " id=" << id << endl; } };
測試
void test_class() { A* buf = new A[3]; //默認構造函數調用3次 調用順序 0-1-2 //A必須有默認構造函數 引文new A[3]調用的是默認構造函數 A* tmp = buf;//記錄A數組的起點位置 cout << "buf=" << buf << " tmp=" << tmp << endl; for(int i = 0; i < 3; i++) { new(tmp++)A(i); //placement new } cout << "buf=" << buf << " tmp=" << tmp << endl; delete[] buf; }
輸出結果
咱們會發現 delete[] 的順序與 new[] 的順序相反,placement後面再說
那麼咱們這個使用不寫[]呢,看看輸出結果會怎麼樣
上面的delete 沒有寫[], 3個class A的內存是釋放了,可是隻調用了一次析構函數.
三 placement new
placement new容許咱們將object建立與 已經申請好的內存中,可是沒有所謂的 placenment delete,由於根本沒有分配內存,因此沒有placement delete
可是有被稱做的placement delete後面說.先看一下placement new
char* buf = new char[sizeof(A) * 3];//申請了3個A的內存 A* pc = new(buf)A();//運用申請好的buf的內存,在buf上賦值
上面的new(buf)A();就是placement new.
編譯器遇到上面代碼會翻譯成
A * pc; try { void* men = operator new(sizeof(A), buf); //借用內存 pc = static_cast<A*>(mem);//安全轉換 pc->A::A();//構造函數 } catch (std::bad_alloc){ //若失敗 不執行構造函數 }
以上就是三種C++申請內存工具的介紹
參考侯捷<<C++內存管理>>