讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式。本站提示廣大學習愛好者:(讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式)文章只能為提供參考,不一定能成為您想要的結果。以下是讀書筆記 effective c++ Item 16 成對使用new和delete時要用相同的形式正文
下面的場景會有什麼錯?
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>。