C++細節 C++中的malloc/free ,new/delete
首先,malloc/free 是函式,new/delete是一個操作符
下面看一下malloc,free,realloc函式原型 (引用自C++ reference)
malloc/free ,calloc,realloc
malloc
void* malloc (size_t size);
Allocate memory block
Allocates a block of size bytes of memory, returning a pointer to the beginning of the block.
The content of the newly allocated block of memory is not initialized, remaining with indeterminate values.
If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced.
free
void free (void* ptr);
Deallocate memory block
A block of memory previously allocated by a call to malloc, calloc or realloc is deallocated, making it available again for further allocations.
If ptr does not point to a block of memory allocated with the above functions, it causes undefined behavior.
If ptr is a null pointer, the function does nothing.
Notice that this function does not change the value of ptr itself, hence it still points to the same (now invalid) location.
calloc
void* calloc (size_t num, size_t size);
Allocate and zero-initialize array
Allocates a block of memory for an array of num elements, each of them size bytes long, and initializes all its bits to zero.
The effective result is the allocation of a zero-initialized memory block of(num*size)
bytes.
If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced.
realloc
void* realloc (void* ptr, size_t size);
Reallocate memory block
Changes the size of the memory block pointed to by ptr.
The function may move the memory block to a new location (whose address is returned by the function).
The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location. If the new size is larger, the value of the newly allocated portion is indeterminate.
In case that ptr is a null pointer, the function behaves like malloc, assigning a new block of size bytes and returning a pointer to its beginning.
calloc是在記憶體的動態儲存區中分配num塊長度為"size"位元組的連續區域,返回首地址。
malloc是在記憶體的動態儲存區中分配一塊長度為"size"位元組的連續區域,返回該區域的首地址。
malloc和free講述的非常簡單和簡潔,我就realloc翻譯一下,realloc有2個引數,指標ptr,和size
realloc的功能就是修改一個原先已經分配好的空間大小,如果*ptr=NULL,則和malloc一樣,是開闢一個size大小的空間
若ptr非空,則分情況講解,
A第一種情況 realloc(p1,newsize),p1非空,newsize比p1指向的原有空間小,則將尾部空間釋放,使空間變為newsize大小
B第二種情況 realloc(p1,newsize),p1非空,newsize比p1指向的原有空間大,但是這一連續空間的尾部之後空間不足以擴容,則另外開闢一塊大小為newsize的空間,將原有空間內的內容複製到這個空間,並釋放原有空間。並返回一個新地址(指向新開闢的地方)指標。
C第三種情況 realloc(p1,newsize) ,p1非空,newsize比p1指向的原有空間大,尾部空間比較大,則直接在後方進行擴容,指標內容不變。
new/delete
c++繼承c語言,按道理來說使用malloc配套的一些函式足以完成任務,為什麼新增新的操作符?來完成
C語言有malloc 和free,按道理c++動態開闢使用malloc和free也是可以的
但是,對於內建型別,譬如int,float是可以的
但是對於類則不行
class A
{
public:
A();
~ A();
private:
};
A:: A()
{
cout << "構造" << endl;
}
A::~ A()
{
cout << "析構" << endl;
}
定義一個類,使用了建構函式則列印 構造,使用解構函式則列印析構
使用我們的測試程式碼
A count;
A *p1 = new A;
A *p2 = (A*)malloc(sizeof(A));
delete p1;
我們使用了3種 情況
第一種,在棧上建立的count
第二種,new,和delete對應指標p1指向的空間
第三種,malloc在堆上建立的,對應指標p2指向的空間
我在delete後打斷點,會出現下面情況
第一個構造是count呼叫建構函式列印的
第二個是new呼叫建構函式列印的
第三個析構是delete呼叫解構函式列印的
由於主函式還沒結束,count還處於生命週期,並沒有被銷燬,故沒有呼叫析構。
那麼malloc呢?並沒有呼叫構造,free也不能呼叫解構函式。
new和malloc還有一個區別,malloc建立失敗返回0,new丟擲異常,可以使用try catch來協調。
《c++primer》中涉及,標準庫定義了operator new和operator delete的8個過載版本
new 和delete的實際過程是
new---》operator new-》malloc-》建構函式,返回ptr指標
delete(ptr)-》解構函式-》operator delete-》free
更簡潔的表示,我繪製了下面這個圖
呼叫相應的 operator new(size_t)
函式,動態分配記憶體。呼叫失敗則呼叫 new_handler()
函式用於處理new失敗問題。如果沒有設定 new_handler()
函式或者 new_handler()
未能分配足夠記憶體,則丟擲異常(一般是這樣,書中講解是有和malloc相同的返回空)。“new運算子”所呼叫的 operator new(size_t)
函式,按照C++的名字查詢規則,首先做依賴於實參的名字查詢(即ADL規則),在要申請記憶體的資料型別T的 內部(成員函式)、資料型別T定義處的名稱空間查詢;如果沒有查詢到,則直接呼叫全域性的 ::operator new(size_t)
函式。在分配到的動態記憶體塊上 初始化 相應型別的物件(建構函式)並返回其首地址。如果呼叫建構函式初始化物件時丟擲異常,則自動呼叫 operator delete(void*, void*)
函式釋放已經分配到的記憶體。
這個具體解釋可以參考《c++primer》記憶體耗盡,稱之為定位new。
我們需要注意的是operator delete和operator new 是標準庫函式,這些函式不僅僅new他們可以呼叫,普通函式也可以呼叫的。
這也就解釋了引入new和delete的原因
而new[]和delete[]則是針對一組物件,原理和功能是一樣的,只需要注意這些函式或者操作符是搭配使用的。