C 記憶體管理

2021-09-10 13:39:54 字數 4371 閱讀 3578

過載operator new 函式

過載operator new 函式

取消析構函式的注釋

從上到下越接近作業系統

分配釋放

類屬可否過載

malloc()

free()

c函式不可

newdelete

c++表示式

不可::operator new()

::operator delete()

c++ 函式

可allocator::allocate()

allocator::deallocate()

c++標準庫

可自由設計來搭配容器使用

當呼叫 new的時候 事實上呼叫的時 ::operator new()

比如 int* pi = new int;

編譯器事實上會執行時的時 pi = static_cast(::operator new(sizeof(int)));

這裡的 operator new 是個全域性函式,可以被過載,如果不去過載它,則編譯器會呼叫預設的operator new 函式

operator new 的函式定義邏輯如下:

void* operator new(size_t size, const std::nothrow_t&) _throw0()

return(p);

}

如果malloc 成功,則p != 0 return p, 返回成功分配的位址

如果malloc 不成功, 則 p==0 調函式_callnewh函式,

正常情況下的new表示式

#include using namespace std;

int main(void)

catch (std::bad_alloc& e) }

cout << "done" << endl;

#if defined(_win32)

system("pause");

#endif // defined(_win32)

return 0;

}

執行結果:

分析: 因為不斷的呼叫了new, 也就是::operator new, 最終導致堆空間不足,所以最終丟擲了std::bad_alloc異常。

設定new_handler但不拋異常

#include using namespace std;

void new_handler()

int main(void)

catch (std::bad_alloc& e)

} cout << "done" << endl;

#if defined(_win32)

system("pause");

#endif // defined(_win32)

return 0;

}

執行結果

分析:當記憶體不夠用時,_callnewh呼叫了 註冊過的 ::new_handler,所以_callnewh返回值為1,但::new_handler 並沒有做什麼記憶體釋放的工作,沒有產生空閒的堆空間,但卻不丟擲異常,此時::operator new 就陷入了死迴圈,註冊過的::new_handler會一直被呼叫。 ps new_handler的作用時為了在記憶體不夠時,在這個函式中清理一些記憶體來**新開闢的需求。

設定new_handler 並丟擲異常

#include using namespace std;

void new_handler()

int main(void)

catch (std::bad_alloc& e)

} cout << "done" << endl;

#if defined(_win32)

system("pause");

#endif // defined(_win32)

return 0;

}

執行結果:

分析:嗯,, 這個應該很好理解。

如果想不拋異常呢

int *p = new(std::nothrow)[size];
這樣 如果 分配不到記憶體,則返回乙個null(0), 克通過p 是否 為 null 來判斷是否分配成功。

#include using namespace std;

inline void * operator new(size_t size)

int main(void)

catch (std::bad_alloc& e)

} cout << "done" << endl;

#if defined(_win32)

system("pause");

#endif // defined(_win32)

return 0;

}

執行結果

分析:當 呼叫 new 時呼叫了 過載的 void* operator new (size_t size); 方法,當malloc 不能再分配時p == null,丟擲std::bad_alloc 異常。

#include using namespace std;

inline void * operator new(size_t size)

inline void* operator new(size_t size)

struct complex

//~complex()

};int main(void)

catch (std::bad_alloc& e)

cout << "done" << endl;

#if defined(_win32)

system("pause");

#endif // defined(_win32)

return 0;

}

執行結果

分析這裡的new ( p) int(4) 這種形式叫做placement new, 是通過乙個指標呼叫建構函式, new§ 事實上的函式形式是 operator new(size_t, void* ) 也可以被過載,編譯器預設的處理方式就是 返回 指標本身。

這裡過載了operator new 函式,所以在使用 new 時就不去呼叫 operator new函式而是呼叫 operator new 函式。這裡一共new 了 2 個complex 物件,乙個complex 由2個double 組成(16個位元組), 2個一共32個位元組。這裡我故意注釋掉了析構函式,因為如果乙個物件有析構函式,那麼在開闢物件陣列時還需要再多開闢size_t個位元組(x86: 4個位元組, x64: 8個位元組),以確保能正確的儲存物件的個數,以正確的對每個物件呼叫析構函式。

#include using namespace std;

inline void * operator new(size_t size)

inline void* operator new(size_t size)

struct complex

~complex()

};int main(void)

執行結果

分析這裡 malloc 的位址是…50 但最終pi 的位址是…58 ,因為返回時,編譯器對位址進行了+8(編譯器實現,過載時不需要實現) ,而這8個位元組剛好存放的就是 2 ,物件的個數,再呼叫delete 時會檢查高sizeof(size_t)位存放的數值,從高位址向低位址對物件呼叫析構函式。

同樣的過載operator delete(void* ptr) 時也存在編譯器預先做好的工作,當過載 operator delete(void* ptr) 時當每個物件的析構函式都已經呼叫完成後才會呼叫該operator delete函式。

C 記憶體管理 C 記憶體分類

c 記憶體管理 記憶體分類 moakap 在編寫程式過程中,程式設計師必須清楚程式記憶體的分配機制,合理進行記憶體管理,這樣才能得到高效的程式。同時,如果對c 記憶體分配基本概念不理解,使用不當,一方面浪費了寶貴的記憶體資源,降低了程式執行效率,另一方面還會造成程式中意想不到的錯誤。在 c 程式中,...

C 記憶體管理

在嵌入式系統中使用c 的乙個常見問題是記憶體分配,即對new 和 delete 操作符的失控。具有諷刺意味的是,問題的根源卻是c 對記憶體的管理非常的容易而且安全。具體地說,當乙個物件被消除時,它的析構函式能夠安全的釋放所分配的記憶體。這當然是個好事情,但是這種使用的簡單性使得程式設計師們過度使用n...

c 記憶體管理

這裡對我暫時所了解的記憶體機制做個記錄,以後再補。首先是記憶體分配 記憶體主要分為3個部分 一是從靜態儲存區域分配。編譯時分配好,主要存放全域性變數,static變數,程式結束釋放。二是從堆疊區域分配。函式內區域性變數存放的地方。隨變數生命週期自動釋放。效率較高,但大小有限。三是從記憶體池分配,即從...