前言
最近在看侯捷老師的內存管理這門課,整理一下課程中的知識和自己的思路。
正文
1.new
在c++的使用中,我們使用new手動申請堆區內存。下面看一下new到底幹了什麼。
舉個例子:
Complex * pc = new Complex(1,2);
這行代碼是使用new創建一個Complex型的對象。
在底層編譯器實際上是完成下面的事情:
Complex *pc;
try
{
void* tmp = operator new(sizeof(Complex)); // 調用operator::new 分配內存
pc = static_cast<Complex*>(tmp); //轉換類型
pc->Complex::Complex(1,2); // 調用構造函數(這種形式是編譯器實現的形式,只有部分平臺可以直接以這種形式調用構造函數)
}
catch(std::bad_alloc)
{
// 內存分配失敗就不執行構造函數
}
所以我們看到了,調用new表達式會執行兩個步驟:
1.調用operator::new 分配內存
2.調用構造函數
需要注意的是,如果內存分配失敗,會拋出異常,將不會調用構造函數。
那麼operator::new 幹了什麼?
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{ // try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
{
if (_callnewh(size) == 0)
{
_THROW_NCEE(_XSTD bad_alloc, );
}
return (p);
}
我們看到,operator::new 實際上是調用了 malloc函數,並且如果malloc失敗,會調用callnewh,如果成功,則會再malloc一次,否則拋出異常。
那麼callnewh實際上就是調用new_handler(當內存分配失敗時的回調函數),我們可以在函數中自己設定功能(比如釋放掉一些無關緊要的內存,或結束程序等等)。當進行這些處理後如果還是分配失敗,就說明真的沒有內存給它分配了,就拋出異常。
可以使用_set_new_handler來設定callnewh所調用的函數。
總結:
1.調用operator::new函數申請空間(operator::new 調用 malloc函數),申請失敗拋出異常。
2.調用static_cast將空間的類型轉換爲目標類型。
3.調用構造函數(簡單數據類型不需要)。
2.delete
舉同一個例子:
delete pc;
pc->~Complex();
operator delete;
先是調用了對象的析構函數,然後調用operator::delete。
void operator delete(void *p)
{
free(p);
}
由operator::delete調用free來釋放內存。
總結:
1.調用對象析構函數(簡單數據類型不需要)。
2.調用operator::delete函數(operator::delete 調用 free)。