程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式

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

編輯:關於C++

讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式。本站提示廣大學習愛好者:(讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式)文章只能為提供參考,不一定能成為您想要的結果。以下是讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式正文


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>。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved