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