【C++】一種典型隱祕的屢次delete的狀況

本文介紹分析一種屢次delete動態內存的狀況。說是典型,是由於這個問題已經在我兩個同事身上發生過;說是隱祕,是由於一旦發生問題,靠肉眼很難肯定緣由。linux

預備知識

不一樣於C語言經過mallocfree等函數實現動態內存的分配和釋放,C++引入了newdelete運算符實現。基本的用法以下:函數

int* p = new int;
delete p;

若是上述代碼的p屢次釋放會出現什麼狀況呢?性能

int* p = new int;
delete p;
delete p;

很明顯會引發程序崩潰,這是我本地執行的錯誤信息,錯誤提示也給出了double free的字樣,告訴咱們這多是兩次釋放致使的問題。spa

double free or corruption (fasttop): 0x0000000001029c20 *
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x70bfb)[0x7f6469dbcbfb]
/lib/x86_64-linux-gnu/libc.so.6(+0x76fc6)[0x7f6469dc2fc6]
/lib/x86_64-linux-gnu/libc.so.6(+0x7780e)[0x7f6469dc380e]
...

這種狀況有沒有簡單的規避方式嗎?我看到好多人這麼寫:指針

int* p = new int;
delete p;
p = nullptr; //或 p = NULL;
delete p;

因爲C++中delete空指針是不出錯的,因此執行不會出錯。code

基於工程上的考慮,delete一個指針後,要把指針賦值爲空指針,藉此提升代碼健壯性。但這每每會掩蓋問題,使得問題查找更難,好比上述問題,咱們應該去分析爲何兩次delete,而不是經過p = nullptr; 暫時掩蓋問題。對象

上面狀況更好的解決方式是使用智能指針或RAII,儘可能在高層代碼裏不混雜底層邏輯。在此不絮叨了,進入下一部分。ip

問題

將問題場景簡化爲如下的例子:內存

class List {
public:
    List() { count = 0; elements = nullptr; } //空列表
    List(int num) : count(num), elements(new int[num]) {} //num個元素的列表

    ~List() { count = 0; delete [] elements; }

private:
    int *elements;//元素的首地址
    int count;  //元素的個數
};

void processList(List ls) {

}

int main() {
    List list(5);

    processList(list);
}

問題的根源出在C++默認的拷貝是「淺拷貝」,即只拷貝當前變量類型所佔用的內存。下面按代碼執行步驟分析:
(1)List list(5);
創建一個對象,該對象{count=5, elements=x}
(2)傳入processList
因爲是淺拷貝,此時ls變量的值爲{count=5, elements=x},即與main中的list共用elements
(3)processList函數體結束
因爲ls對象即將超出做用域,編譯器會調用ls的析構函數,此時ls變量的值爲{count=0, elements=無效地址x},因爲listls共享elements,因此main中的elements變量的值爲{count=5, elements=無效地址x}
(4)main函數體結束
list也即將超出做用域,編譯器調用list的析構函數,因爲其elements已經被delete了,再釋放一次會出現內存錯誤,致使程序終止。element

那怎麼修正這個問題呢?只要將processListls改成引用傳參便可,引用傳參僅將使用權傳給函數,全部權還屬於原對象,因此不會執行析構函數。

void processList(List& ls) {

}

固然,還有一種方式是改寫重載賦值和拷貝構造函數,實現「深拷貝」,這樣也能解決問題。標準庫中的stringvector是較經常使用的類,因此自己實現了深拷貝,因此不會出現以上問題。在包含的元素較多時,須要考慮性能問題。

C++的零成本抽象,帶來性能優點的同時,必定也要細細考慮其帶來的複雜成本。好比,GC 用爽的人極可能即會犯以上的錯誤,每每不是由於不知道,而是由於相關意識不強烈。因此,必定要當心,當心,再當心。

請關注個人公衆號哦。

clipboard.png

相關文章
相關標籤/搜索