天天看點

C++細節 C++中的malloc/free ,new/deletefreecallocrealloc

首先,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後打斷點,會出現下面情況

C++細節 C++中的malloc/free ,new/deletefreecallocrealloc

第一個構造是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

更簡潔的表示,我繪制了下面這個圖

C++細節 C++中的malloc/free ,new/deletefreecallocrealloc

調用相應的 

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[]則是針對一組對象,原理和功能是一樣的,隻需要注意這些函數或者操作符是搭配使用的。