malloc,free,new,delete解析(原)
??? 使用C/C++的苦逼娃們經常深陷內存越界錯誤,資源泄漏錯誤等等問題,而且這樣的慘劇每時每刻都在這個世界上重復的發生著。其實,我也是苦逼娃!也為了個神馬越界的東西debug了整個下午過,為此也想砸電腦過。最后想想,其實不是C/C++苦逼,是我們的不小心而造成如此的苦逼。罪過,罪過。。。
??? 在C語言庫中,提供了這么兩個函數,malloc和free,分別用于執行動態內存分配和釋放。兩個函數的聲明如下:
void* malloc(size_t size); void free(void *pointer);??? 從外觀上看,malloc函數的參數是接受需要分配的內存字節數,如果內存能夠滿足請求量,那么將會返回:指向被分配的內存塊起始位置的指針(引用自《C和指針》中的表述)。而且,這塊內存是一塊連續的內存。夠爽吧!如果分配不成功的話,那么就返回null指針。例如:
struct Node { data_type value; struct Node *pre_node; struct Node *next_node; }; ? typedef struct Node *List; ? List newnode = NULL; ? newnode = (List)malloc(sizeof(struct Node)); // 分配了Node的空間,返回了相應的指針 ? if (!newnode) // 為了防止空指針的存在,要檢查是否分配成功 { printf("內存分配不成功!\n"); exit(1); }??? 在這里,我們又一次看到了void指針的功效。對于不同類型的指針轉換,void指針都能應付自如,更重要的是,我們不用為每種類型都特化一個內存分配版本。這個會累死的。還有,對于分配出來的指針,我們要檢查它是否為空,這是為什嗎?因為,對于空指針的操作將會帶來未知的錯誤,所以錯誤摁在萌芽階段是我們的義務和責任。
??? 內存的東西,向來都是要有借有還。有malloc就會有free。free函數的作用就是負責釋放申請來的內存的。這個指向釋放的內存指針是有講究的,你不能釋放申請來的一小部分的區域。例如:
int *pi; ? pi = (int *)malloc(sizeof(int)*10); ? free(pi + 5); // 這里就苦逼了!??? 其次,較為常見失誤在于,我們對申請的內存指針進行操作,操作完之后,對其進行釋放。此時,釋放不成功的原理和上面這個例子一樣,釋放了部分的內存,而不是釋放全部內存。一般的做法是設一個臨時變量保存malloc來的指針,在釋放的時候,就釋放這個指針所以的內存區域,這樣就不會出錯了。
??? 關于內存越界,這是一個很普遍的問題。這個只能你去親自把握,記清楚你申請了多少,其邊界在哪里,不要出錯就埋怨電腦。
??? 說了malloc和free,那就進入今天的主題new和delete了。
??? 想必我們都寫過這樣的代碼吧。
string *str = new string("memory alloc!");??? 我們都知道new在堆上創建了一個string類型對象,這個看似一個動作的事情卻暗地包含了三件事:獲得一塊內存空間、調用構造函數、返回正確的指針。相當于下面:
??? 你應該會心里犯嘀咕,臥槽,怎么出現了這么多的環節。其實呢,new可分為這么三種情形:new operator(我們平常用的new), operator new(用來分配內存的),placement new(構造對象的)。當然,你要用placement new的時候,你要加入<new>的頭函數。
??? ⑴ new operator
??? new operator的第一步分配內存實際上是通過調用operator new來完成的,這里的new是可以重載的。operator new默認情況下首先調用分配內存的代碼,嘗試得到一段堆上的空間,如果成功就返回,如果失敗,則轉而去調用一個new_hander,然后繼續重復前面過程。
#include <iostream> using namespace std; ? class MyClass { private: ? public: MyClass() { }; ? void* operator new(size_t size) { cout << "調用了operator new" << endl; return ::operator new(size); } }; ? int main() { MyClass *a = new MyClass(); return 0; }??? 運行的結果如下:
??? 相應的,delete也有delete operator和operator delete之分,后者也是可以重載的。并且,如果重載了operator new,就應該也相應的重載operator delete。
⑵ placement new
??? placement new的作用是用來實現定位構造對象,可以說相當于new operator三步操作中的第二步,也就是在取得了一塊可以容納指定類型對象的內存后,在這塊內存上構造一個對象。其用法:
void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }??? 其格式是這樣的:new(指針指向的內存地址) 類型(值)。對照格式,可以這么說是在__p上構造一個_Tp類型的,值為__val。
??? 如果是像上面那樣在棧上使用了placement new,則必須手工調用析構函數:
void destroy(pointer __p) { __p->~_Tp(); }??? 當覺得默認的new operator對內存的管理不能滿足我們的需求,我們可以自己手工打造內存管理,此時的placement new就相當有用了。以上兩段代碼源于sgi stl的alloc中,就說明問題了。
⑶ new operator 和 operator new 的取舍
??? 兩個關鍵詞很容易讓人迷糊,兩者又都是骨肉相連的狀態,取舍有點不易。對于取舍的評判,我挪用了《more effective C++》中的觀點:“如果你想產生對象在heap上,那么就用new operator,它不但分配內存,而且為該對象調用了構造函數;如果你只打算分配內存,那么就用operator new ,只分配內存,其余的事情都沒做。當然,使用operator new 后續的對象構造也要跟上,不然但分配內存也就沒有意義了。”
??? 總結,在這篇文章中,介紹了malloc,free,new,delete的使用和一些心得體會。當然,還有許多的內容沒有做相應的介紹,比如new_handle等內容。抱歉,抱歉!
??? 關于內存分配的問題,你還可以參考:內存分配機制。這篇文章介紹了C/C++內存分配的知識。
參考文獻
1. 《C語言程序設計》
2. 《C和指針》
3. 《C專家編程》
4. 《more effective C++》
5. 《STL源碼解析》
轉載于:https://www.cnblogs.com/ComputerG/archive/2012/03/10/2389328.html
總結
以上是生活随笔為你收集整理的malloc,free,new,delete解析(原)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL SERVER 2005 同步复制
- 下一篇: Eclipse 自动注释的设置