C++内存泄露几种常见原因
在cpp編程中,產生內存泄漏的主要原因是利用malloc或者new等分配內存的方式申請內存后,由于主觀或者客觀原因沒有進行釋放,導致申請的內存區域沒有及時得到釋放導致的。
下面對幾種常見/特殊的情況進行簡單記錄。
1. 析構函數中未匹配地釋放內存
2. 基類的析構函數沒有設為虛函數,
由于基類的析構函數不是虛函數,在實現多態時,通過delete刪除指向派生類的基類指針時,派生類的析構函數被覆蓋無法調用,而是調用的基類的析構函數,導致派生類對象無法被釋放,導致內存泄漏。
3. 關于指針數組釋放
對于二維數組,利用指針的定義區別如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | int?(*a)[N]=new?int[M][N];??//N必須為已知 //對應內存釋放為 delete[] a; int?**b=new?int*[M]; for(int?i=0;i<M;i++) { ????????b[i]=new?int[N];? } //對應內存釋放為 for(int?i=0;i<M;i++) { ????????delete[] b[j];????? } delete[] b; |
delete[]不光需要釋放對象的空間,還要釋放其中的每個指針,否則釋放的不徹底。
4. 拷貝構造函數和運算符重載的問題
當類缺少拷貝構造函數時,可能造成內存泄露問題。具體場景主要是當一個類中有指針成員,但是沒有編寫拷貝構造函數時,系統將會調用默認構造函數,采用值傳遞的方式。這種隱式傳遞的方式容易造成兩個對象同時具有指向同一個地址的指針成員。因此在釋放對象的時候,第一個對象能夠正常釋放,而第二個對象的釋放將會釋放相同的內存,這是一種錯誤的做法,可能會導致堆的崩潰。因此當類中含有指針成員時,應當顯示地重寫構造函數和重載運算符,以保證深拷貝的發生。
5.?shared_ptr的循環引用問題
身為智能指針的shared_ptr也可能存在內存泄露問題。如下面情況
當類A和類B中分別含有類型為對方的智能指針,并且在各自創建實例a和b后,對實例a/b中的智能指針傳入b/a進行了賦值。那么在離開作用域后,實例a和實例b中的智能指針引用計數都是1,但是都在等待對方釋放后才能釋放,這種情況便造成了循環引用的問題。具體代碼實例如下:
class ClassA { public:...void setInnerPtr(shared_ptr<ClassB> pB) {p = pB;} private:shared_ptr<ClassB> p; };class ClassB { public:...void setInnerPtr(shared_ptr<ClassA> pA) {p = pA;}private:shared_ptr<ClassA> p; }; int main() {shared_ptr<ClassA> pA = make_shared<ClassA>();shared_ptr<ClassB> pB = make_shared<ClassB>();pA->setInnerPtr(pB);pB->setInnerPtr(pA);... }這種情況可以引入weak_ptr來解決,在ClassA和ClassB的聲明中用weak_ptr代替shared_ptr后,不會產生引用計數,因此不會產生循環引用的問題。
其他會造成野指針的情況:
1)指針變量沒有被初始化(如果值不定,可以初始化為NULL)
2)指針所指內存被釋放后,沒有置為NULL。
3)指針操作超越了變量的作用范圍,比如返回指向棧內存的指針就是野指針。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的C++内存泄露几种常见原因的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下内存问题检测神器 valgr
- 下一篇: select、poll、epoll之间的