在C++中,你真的會用new嗎?

摘要:「new」是C++的一個關鍵字,同時也是操做符。關於new的話題很是多,由於它確實比較複雜,也很是神祕。

本文分享自華爲雲社區《如何編寫高效、優雅、可信代碼系列(2)——你真的會用new嗎》,原文做者:我是一顆大西瓜 。程序員

C++內存管理

1. C++內存分配

C++中的程序加載到內存後按照代碼區、數據區、堆區、棧區進行佈局,其中數據區又能夠分爲自由存儲區、全局/靜態存儲區和常量存儲區,各區所長以下:數組

  • 棧區
    函數執行的時候,局部變量的存儲單元都在棧上建立,函數執行結束後存儲單元會自動釋放。棧內存分配運算內置於處理器指令集中,效率高,但分配內存容量有限。
  • 堆區
    堆就是new出來的內存塊,編譯器無論釋放,由應用程序控制,new對應delete。若是沒釋放掉,程序結束後,操做系統會自動回收。
  • 自由存儲區
    C中malloc分配的內存塊。用free結束生命週期。
  • 全局/靜態存儲區
    全局變量和靜態變量被分配到同一塊內存中,定義的時候就會初始化
  • 常量存儲區
    比較特殊的存儲區,存放常量,不容許修改。

堆和棧的區別函數

  • 管理方式
    棧由編譯器自動管理,堆由程序員控制
  • 空間大小
    32位系統下,堆內存能夠達到4GB,棧有必定的空間大小
  • 碎片管理
    對於堆,頻繁的new/delete確定形成內存空間的不連續,產生大量內存碎片下降程序效率;棧因爲遵循先進後出的規則,不會產生空隙
  • 生長方向
    堆是向上生長的,即向着內存地址增長的方向增加;而棧是向着內存地址減少的方向增加的
  • 分配方式
    堆是動態分配的,棧有動態分配和靜態分配之分:靜態分配由編譯器完成,動態分配由alloca函數完成,即便是動態分配,依然是編譯器自動釋放
  • 分配效率
    計算機底層提供了棧的支持,分配了專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這決定了棧的效率會比較高。堆則是由C/C++函數庫提供的,機制比較複雜,好比爲了分配某個大小的內存須要在堆內存中搜索可用足夠大小的空間,效率比棧要低的多

2. new/delete和new []/delete []

  • 回收new分配的單個對象內存空間時用delete,回收用new[]分配的一組對象時用delete[]
  • 對於內置類型(int/double/float/char/…),因爲new[]申請內存時,編譯器還會悄悄在內存中保存整數,表示指針數組的個數,因此delete/delete[]均可以正確釋放所申請的內存空間
  • 建議在調用new時使用的[],那麼調用delete也使用[]

3. new的三種形態

  • new operator 經常使用的new,語言函數內建,不能重載。調用過程當中實際完成的有三件事:
  1. 爲類型對象分配內存;
  2. 調用構造函數初始化內存對象;
  3. 返回對象指針
    若是是在堆上創建對象,直接使用new operator。
  • operator new 普通操做符,能夠重載。若是僅僅是分配內存,那麼應該調用operator new,但不負責初始化。系統默認提供的分配器在時間和空間兩方面都存在一些問題:分配器速度較慢,分配小型對象時空間浪費嚴重,重載new/delete有三方面好處:
  1. 改善效率
  2. 檢測代碼中的內存錯誤
  3. 得到內存使用的統計數據
  4. C++標準規定,重載的operator new必須是類成員函數或全局函數,全局的operator new重載不該該改變原有簽名,而是直接無縫替換原有版本。全局重載頗有侵略性,別人使用你的庫沒法使用默認的new,而具體類的重載只會影響本class和其派生類,可是類的operator new函數重載必須聲明爲static,由於operator new是在類的具體對象被構建出來以前調用的。
  5. 爲了得到2和3的優點,重載的operator new須要以下函數聲明void* operator new(size_t, const char* file, int line);
  • placement new 定義在庫<<new>>中。若是想在一塊已經得到內存裏創建對象,那麼應該調用placement new。一般狀況不建議使用,但在某些對時間要求很是高的應用中能夠考慮,由於選擇合適的構造函數完成對象初始化是一個時間相對較長的過程。

 

點擊關注,第一時間瞭解華爲雲新鮮技術~佈局

相關文章
相關標籤/搜索