讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式

来源:http://www.cnblogs.com/harlanc/archive/2017/02/21/6422351.html
-Advertisement-
Play Games

1. 一個錯誤釋放記憶體的例子 下麵的場景會有什麼錯? 一切看上去都是有序的。new匹配了一個delete。但有一些地方確實是錯了。程式的行為是未定義的。至少來說,stringArray指向的100個string對象中的99個看上去都不能被正確釋放,因為他們的析構函數可能永遠不會被調用。 2. 使用n ...


1. 一個錯誤釋放記憶體的例子

下麵的場景會有什麼錯?

1 std::string *stringArray = new std::string[100];
2 
3 ...
4 
5 delete stringArray

 

一切看上去都是有序的。new匹配了一個delete。但有一些地方確實是錯了。程式的行為是未定義的。至少來說,stringArray指向的100個string對象中的99個看上去都不能被正確釋放,因為他們的析構函數可能永遠不會被調用。

2. 使用new 和delete時究竟做了啥?

當你使用一個new表達式(通過使用new動態的創建一個對象)時,會發生兩件事情。第一,記憶體被分配(通過一個叫做operator new的函數,看Item 49和Item 51)。第二,在分配的記憶體上調用了一個或多個構造函數。當你使用一個delete表達式時,另外兩件事情會發生:在記憶體上調用了一個或者多個析構函數,然後記憶體被解除分配(通過調用叫做operator delete的函數,見 Item 51)。關於delete的一個重要的問題是:在即將被刪除的記憶體中究竟有多少對象?這個問題的答案決定了有多少個析構函數必須被調用。

 

3. new和delete不配對使用為啥會出錯?

實際上,下麵這個問題更加簡單:被刪除的指針是指向一個單獨的對象還是指向數組的所有對象?這是個關鍵的問題,因為單個對象的記憶體分配通常情況下同數組的記憶體分配是不一樣的。特別的,一個數組的記憶體通常包含了數組的大小,因此delete很容易就會知道需要調用多少個析構函數。單個對象的記憶體卻沒有這樣的信息。你可以將記憶體不同分配想象成下麵這個樣子,n是數組的大小:

 

當然這隻是一個例子。編譯器不需要這麼實現,雖然很多編譯器確實是這麼實現的。

當你在一個指針上使用delete時,delete能夠知道數組容量信息是否存在的唯一方法就是通過你來告訴它。如果當你使用delete時用了“[]”,delete認為指針指向一個數組。否則,它會認為它在指向一個單一的對象:

1 std::string *stringPtr1 = new std::string;
2 
3 std::string *stringPtr2 = new std::string[100];
4 
5 ...
6 
7 delete stringPtr1; // delete an object
8 
9 delete [] stringPtr2; // delete an array of objects

 

4. new和delete不配對使用會有什麼後果?

如果你在stringPtr1上使用“[]”將會發生什麼?結果是未定義的,但是結果不會太好。假設記憶體分佈如上圖所示,delete會讀取一些記憶體並把它所讀到的解釋為一個數組容量,接下來就開始多次調用析構函數,卻忽略的以下事實:它處理的記憶體不但不是一個數組,也可能並沒有包含它正忙著釋放的那種類型的對象。

如果你不在stringPtr2上使用“[]”會發生什麼?結果也是未定義的,但是你可以看到這會導致過少的構造函數被調用。此外,對於像int的內建類型來說結果也是未定義的(有時甚至是有害的),雖然內建類型沒有析構函數。

規則很簡單:如果你在一個new表達式中使用”[]”,你必須在對應的delete表達式中使用”[]”,反之亦然

當你實現一個包含指向動態分配記憶體的指針的類,並且同時提供多個構造函數的時候,你需要將上面的重要規則記在心中,因為你必須當心在對構造函數中對指針成員進行初始化時,new必須使用相同的形式。如果你不這麼做,你又怎麼能知道在析構函數中將使用什麼形式的delete呢?

5. 使用typedef時需要註意new和delete的配對使用

對於傾向於使用typedef的人來說這條規則同樣值得註意,因為這意味著typedef的作者必須指出使用new來創建typedef類型的對象時,使用什麼形式的delete對其進行銷毀。看下麵的例子:

1 typedef std::string AddressLines[4]; // a person’s address has 4 lines,
2 
3 // each of which is a string

 

因為AddressLines是一個數組,new應該這麼使用:

1 std::string *pal = new AddressLines; // note that “new AddressLines”
2 
3 // returns a string*, just like
4 
5 // “new string[4]” would

使用delete的形式必須和new相匹配:

1 delete pal; // undefined!
2 
3 delete [] pal; // fine

 

為了避免這種混淆,不如放棄在數組類型上使用typedef。這很容易,因為標準c++庫(見Item 54)中包含string,vector和模板,使得對動態分配數組的需求幾乎將為0。這裡我們舉個例子,AddressLines可以被定義成由strings組成的vector,也就是類型 vector<string>。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 文檔目錄 本節內容: 簡介 安裝 創建工作 調度工作 更多 簡介 Quartz 是一個功能完整的開源工作調度系統,可用於最小的應用到一個大型的企業系統.Abp.Quartz 包簡單地把Quartz集成到ABP中. ABP已經內置後持久化的台作業和工作者,如果你有更高的調度上的需求,Quzrtz是一個 ...
  • 一、Parallel的使用 在Parallel下麵有三個常用的方法Invoke、For和ForEach。 1、Parallel.Invoke 執行Parallel.ParallelInvokeMethod()的結果: 可以看出正常調用Run1()和Run2()所花費的時間在5秒左右,而用Parall ...
  • 在ASP.NET MVC框架中,將視圖中的數據傳遞到控制器中,主要通過發送表單實現的。具體使用中,主要使用以下三種方法。 1.通過Request.Form讀取表單數據 表單代碼: 使用Request.Form提取表單數據: 2.通過FormCollection讀取表單數據 3、直接讀取表單數據對象 ...
  • 2017年我們將聚集在打磨我們的控制項,使wijmo更易於使用,增加一些重要的新控制項 ...
  • 今天更新了一個網站,新增了一個頁面,調用WebService,在測試環境好好的,部署到正式環境後就莫名報錯: 伺服器提交了協議衝突. Section=ResponseStatusLine 網上查了好多解決方案,有說加這個配置節的: 然而並沒有什麼卵用啊! 一個偶然的發現,讓我找到了真正的原因。 我在 ...
  • 今天一個兼職結束了,又要開始尋找新的兼職公司了 ,為了貼補家用啊,為了給兒子更好的生活加油! 抒情完畢進入正題,本篇文章要解決的問題是其實在開發微信支付,微信公眾號等回調地址必須是外網可訪問的80埠地址,這就導致很多開發上的不便,網上應該有很多教程做類似的了我這篇重覆造輪子一是記錄一下以備自己將來 ...
  • 數據驗證控制項 --之心 在ASP中進行表單數據驗證時,通常開發者必須自己編寫一套驗證的規則,然後自己將這些代碼拷貝到ASP代碼中對錶單進行驗證。這樣進行驗證的方式實在不太方便,幸運的是,ASP.NET解決了這個問題,這就是數據驗證Web控制項。 數據驗證控制項是ASP.NET中專門用來驗證表單用戶輸入的 ...
  • 20170220問題解析請點擊今日問題下方的“【Java每日一題】20170221”查看(問題解析在公眾號首發,公眾號ID:weknow619) 今日問題: 請問該程式運行結果是什麼?(點擊以下“【Java每日一題】20170221”查看20170220問題解析) 題目原發佈於公眾號、簡書:【Jav ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...