C++的malloc和new的區別
1.對於C++而言,malloc是函式,但是new是運算子
看似函式和運算子實現的功能都差不多。但是對於C++來說,new是運算子就意味著我們可以進行運算子過載,這就意味著我們可以定製我們自己的new記憶體分配器。
同時,由於C++特有的異常處理機制,我們不但可以在我們記憶體分配失敗的時候,new返回一個null,同時也可以報出一個bad_alloc錯誤,同時呼叫我們的new_handler(new運算子錯誤處理程式),但是我們的new_handler應該如何寫呢。
還是先來一段程式碼:
class NewHandlerHolder
{
public:
explicit NewHandlerHolder(std ::new_handler nh):handler(nh) //取得目前的new-handler.釋放它
~NewHandlerHolder()
{std::set_new_handler(handler); }
private:
std::new_handler handler; //記錄下來,阻止copying
NewHandlerHolder(const NewHandlerHolder&);
NewHandlerHolder& operator=(const NewHandlerHolder&);
};
void * Widget::operator new(std::size_t size) throw(std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler)); //安裝Widget的new-handler.
return ::operator new(size); //分配記憶體或丟擲異常.恢復global new-handler.
}
template<typename T> //"mixin"風格的base class,用以支援
//class 專屬的set_new_handler
class NewHandlerSupport
{
public:
static std::new_handler set_new_handler(std::new_handler p)throw();
static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handler currentHandler;
};
template<typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(std::new_handler p) throw()
{
std::new_handler oldHandler=currentHandler;
currentHandler=p;
return oldHandler;
}
template<typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size) throw(std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler));
return ::operator new(size);
}
//以下將每一個currentHandler初始化為null
template<typename T>
std::new_handler NewHandlerSupport<T>::currentHandler=0;
上面的程式碼,將我們過載的New以及new_handler函式封裝成了一個類使用。但是,這裡要注意的是,如果我們多重繼承這個NewHandler類,要看適不適合我們的類,否則將會出現錯誤。
2.對於C++而言,new運算子可以動態申請我們的一個物件的空間
這裡,我還是以一個例子來說明new來動態申請我們的一個物件的空間會引發什麼問題:
Example* em=new Example
我們申請一個Example類的物件的時候,一共做了兩件事:
1.類似malloc的過程申請了一塊空間。
2.呼叫Example類的建構函式。
但是如果在第二步的時候,程式丟擲了異常。那麼是不是代表著new的過程失敗了,丟擲一異常,返回了null。第一步申請的空間還是申請,但沒有得到指標進行delete操作,這就造成了記憶體洩露。
這明顯是我們不想看到的不可控的情況。
實際上解決這個問題的方法也有兩種:
1.對記憶體塊進行簽名。
2.我們每一次new的過程中都要返回一個指向空間的指標就行了。
實際上,我們的C++的new庫已經為我們實現了這個功能:
#include<new>
void* operator new(std::size_t,void* pMemory) throw()
那個pMemory就是指向我們空間的指標啦,這樣即使出現剛剛的情況,我們也可以利用這個指標來進行返回。
還有一種是基於簽名的方式,這裡還是直接上程式碼:
static const int signature=0xDEADBEEF;
typedef unsigned char Byte;
void* operator new(std::size_t size) throw(std::bad_alloc)
{
using namespace std;
size_t realSize=size+2*sizeof(int); //增加大小,使能夠塞入兩個signatures.
void* pMem=malloc(realSize); //呼叫malloc取得記憶體。
if(!pMem) throw bad_alloc();
//將signature寫入記憶體的最前段落和最後段落
//減一個int是為了能夠寫在這個int的地方寫上簽名
*(static_case<int*>(pMem))=signature;
*(reinterpret_case<int*>(static_case<Byte*>(pMem)+realSize-sizeof(int)))=signature;
//返回指標,指向恰位於第一個signature之後的記憶體位置.
return static_cast<Byte*>(pMem)+sizeof(int);
}
可以從程式碼看出,主要做的改動就是把原來申請的空間擴充套件了兩個int的簽名,然後頭尾加上簽名,之後返回的是第一個簽名後的記憶體位置。
但是這樣做可能無法實現的記憶體對齊的要求(記憶體對齊是為了更快的訪問(直接通過記憶體的移位操作進行訪問))。
既然提到了記憶體對齊的問題,這裡就要提一下一個優秀的記憶體分配器應該考慮什麼,我們考慮個性化的記憶體分配器應該考慮什麼?
3.優秀的記憶體分配器應該如何設計考慮
記憶體分配器的具體設計在我的另一篇部落格上有提到:
http://blog.csdn.net/github_33873969/article/details/78571868
這裡我們更專注記憶體分配器的其他方面:
1.執行緒安全(在多執行緒環境下,我們的new過程還是否安全)
2.檔案系統的記憶體對齊問題
3.對於使用記憶體情況的統計問題
4.為了將相關物件成簇集中
這裡我們簡單的提幾點
1.為了保證執行緒安全的時候,我們在new的時候如果對連結串列進行操作需要對連結串列的結點利用鎖機制進行保護。但是這樣就會降低一定量的效果。這就給我們定製new做了一個要求,要在只有單執行緒的環境下把相關鎖關掉。
3.關於使用記憶體情況的統計問題,我們可以在我們的new的過程中,統計我們申請的塊的大小情況,回收與申請的時間間隔如何,他們更傾向於FIFO次序或LIFO(後進先出)次序,之後我們可以再進行合理化定製。
4.為了將相關物件成簇集中。為了考慮區域性性原理,我們可以將相同的物件放在一起,為了能夠得到cache親和,來進行快速訪問。
Reference:Effective C++ (改善程式與設計的55個具體做法)
相關推薦
C++的malloc和new的區別
1.對於C++而言,malloc是函式,但是new是運算子 看似函式和運算子實現的功能都差不多。但是對於C++來說,new是運算子就意味著我們可以進行運算子過載,這就意味著我們可以定製我們自己的new記憶體分配器。 同時,由於C++特有的異常處理機制,我們不
malloc和calloc區別(c)
網上找到的英文解釋如下:Both the malloc() and the calloc() functions are used to allocate dynamic memory. Each operates slightly different from the o
malloc和new的區別
1,malloc與free是C++/C語言的標準庫函式,new/delete是C++的運算子。它們都可用於申請動態記憶體和釋放記憶體。 2,對於非內部資料型別的物件而言,光用maloc/free無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自
linux下brk、mmap、malloc和new的區別
答:brk是系統呼叫,主要工作是實現虛擬記憶體到記憶體的對映,可以讓程序的堆指標增長一定的大小,邏輯上消耗掉一塊虛擬地址空間,malloc向OS獲取的記憶體大小比較小時,將直接通過brk呼叫獲取虛擬地址。 mmap是系統呼叫,也是實現虛擬記憶體到記憶體的對映,可以讓程序
C# show和showdialog區別
更多 comm isp 應該 常見 解釋 方式 不存在 close 簡單地說他們的區別就是show彈出來的窗體和父窗體(上一個窗體的簡稱)是屬於同一等級的,這兩個窗體可以同時存在而且可以隨意切換,但是showdialog彈出來的窗體就不能這樣,他永遠是被置頂的,如果
malloc和new
1.malloc int *p = (int *)malloc(sizeof(int)) 1.calloc void *calloc( size_t num, size_t size ); 函式返回一個指向num 陣列空間,每一陣列元素的大小為size。如果錯誤發生返
c++中->和.的區別
->用在指標型別的類例項的,而.用在例項化物件的指向。 下面是例子 #include <iostream> using namespace std; class Complex { private: double real; double image;
C++/C中!和~的區別與作用
區別: !是邏輯運算子(與||,&&是一類符號),表示邏輯取反,可以把非0值變成0,把0值變為1 ~是位運算子(與|,&是一類符號),表示按位取反,在數值的二進位制表示上,將0變為1,將1變為0 例子: #include<io
c# Invoke和BeginInvoke 區別
Control.Invoke 方法 (Delegate) :在擁有此控制元件的基礎視窗控制代碼的執行緒上執行指定的委託。 Control.BeginInvoke 方法 (Delegate) :在建立控制元件的基礎控制代碼所線上程上非同步執行指定委託。 (一)Control的
c# bitmap和new bitmap(bitmap)
問題情境: 給picturebox賦image屬性,我用一下程式碼,出錯: Bitmap theBitmap = convertCameraData.display(rawDataArray, height, width, rawImageArray, rgbPalette_256, backg
C++類和new、delete操作符和堆和棧記憶體的分配
如果你是Java、C#、PHP程式設計師,那麼會對 new 非常熟悉,在這些程式語言中,只能通過 new 來建立物件。 在C++中,你可以像定義變數一樣來建立物件,如: Studentstu; //物件已被例項化,已分配記憶體空間,可以使用了stu.say();
C/C++ scanf和gets 區別
否則 logs ++ main 區別 %d 添加 stdin 接受 ref https://www.cnblogs.com/hlongch/p/5742477.html scanf和gets都能從輸入流stdin讀取字符串,那麽它們有什麽區別呢? scanf 留回車:開
C-sizeof和strlen區別,以及sizeof如何計算結構體大小
struct alt inf 編譯 style img com 大小 運行 sizeof和strlen區別 sizeof是關鍵字,在編譯時就能計算出值,可以計算任何類型 strlen是函數,只有在運行時才能去計算,且只能計算字符型的. 對於數組時,strlen
你不知道的javascript之Object.create 和new區別
前幾天有碰到原型的問題。之前以為自己對原型還是有所瞭解,但是細細研究,發現自己對原型的理解還是太年輕了。 Object.create 和new 建立物件的方式,我以我碰到的兩種建立方式,Object.create 和new來說明 var B
面試題5——C中的malloc和C++中的new有什麼區別?
malloc和new有以下區別: (1)new,delete是操作符,只能在C++中使用; (2)malloc,free是函式,可以覆蓋,C,C++中都可以使用; (3)new可以呼叫物件的建構函式,對應的delete呼叫相應的解構函式; (4)malloc僅僅分配記憶體,free僅僅回收記
[C/C++] new/delete和malloc/free基本區別
/**便於遺忘時複習**/ 區別一:本質 new/delete 在C++中是運算子不是函式,需要編譯器支援。malloc/free是庫函式,需要標頭檔案支援,在C語言中使用。 區別二:開闢記憶體大小 用 new 操作符申請記憶體分配時無須指定記憶體塊的大小,編譯器會根據提供的型別資訊自行計算。
C++中malloc/free和new/delete的區別---補充(15)《Effective C++》
1、C++中既然有了new/delete為什麼還有還存在malloc/free呢? 1)malloc/free作為C/C++語言中的庫函式,而new/delete是C++中的運算子而已,因此C++編譯器可以強制使new/delete運算子進行建構函式和解構函式
C++中關於[]靜態數組和new分配的動態數組的區別分析
zid dad ima lin aer uem asa iba ash %E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3java%E8%99%9A%E6%8B%9F%E6%9C%BA7---%E7%BA%BF%E7%A8%8B%E5%AE%89%E5
C#中的overrid和new修飾符區別(代碼)
之間 using stat ide post 不同的 虛擬 spa 代碼 在C#的繼承中嘗嘗會用到相關的修飾詞:override和new。這兩個修飾符都可以在新的子類中,重寫同名的父類方法。 override: 擴展或修改繼承的方法、屬性、索引器或事件的抽象或虛擬
C/C++ - malloc/free和new/delete的區分
字節 delete 分別是 自定義 void int eight 構造函數 內存 new/delete與malloc/free的區別主要表現在以下幾個方面: 註意:最主要的區別,new/delete是運算符,而malloc/free是函數 (1)、new能夠自動計算