條款16 成對使用new和delete時要採取相同形式

Sunshine_top發表於2015-03-11

總結:

      如果你在 new表示式中使用了[],你必須在對應的 delete表示式中使用[]。如果你在new表示式中沒有使用[],你也不必在對應的 delete表示式中不使用[]。

        delete的最大問題在於:即將刪除的記憶體之內究竟存在多少物件?這個問題的答案決定了有多少個解構函式必須被呼叫。當你對一個指標使用 delete,唯一能夠讓delete知道記憶體中是否存在一個“陣列大小記錄”的方法就是由你來告訴它。如果你在使用的 delete 中加入了方括號,delete 就認定那個指標指向一個陣列。否則,就認定指向一個單一的物件。

std::string *stringPtr1 = new std::string;
std::string *stringPtr2 = newstd::string[100];
...
delete stringPtr1; //刪除一個物件
delete [] stringPtr2; //刪除一個由物件組成的陣列

     對 stringPtr1 使用了delete []形式和對 stringPtr2 沒有使用delete []形式都會發生令人不愉快的未定義行為。

規則很簡單如果你在 new 表示式中使用了[],你也必須在相應的 delete表示式中使用[];如果你在 new 表示式中沒有使用 [],在匹配的delete 表示式中也不要使用[]。

       當你寫的一個類中包含一個指向動態分配的記憶體的指標,而且提供了多個建構函式的時候,這條規則尤其重要,因為那時你必須小心地在所有的建構函式中使用相同形式的new初始化那個指標成員。否則你怎麼知道在解構函式中應該使用哪種形式的delete呢?

        這個規則對於喜好typedef的人也很值得注目,因為這意味著一個 typedef 的作者必須說清楚,當用new建立一個 typedef 型別的物件時,應該使用哪種形式的delete。例如,考慮以下typedef:

typedef std::string AddressLines[4]; // 每個人的地址有4行,每行是一個string
std::string *pal = new AddressLines;
// 注意"new AddressLines"返回一個string*,就像“new string[4]”一樣
delete pal; // 行為未有定義!
delete [] pal; // fine

        最好儘量不要對陣列形式做typedef動作。這很容易達成,因為C++標準程式庫包含 string 和 vector,而且那些模板將對動態分配陣列的需要減少到幾乎為零。例如,這裡,AddressLines可以被定義為一個string的vector,也就是說,型別為 vector<string>。



相關文章