C++ 可能存在的內存泄漏問題(個人經驗總結)

1.幾乎所有程序員都知道的,使用new申請的內存,已不再使用卻沒被delete;

破解之道:
方法很多,
最基礎方法就是程序員自己注意 new 和 delete 配套出現;
比較高級一點的,就是模仿智能指針,使用引用計數器;
2.new出來的內存,被強轉成其他類型,之後被釋放,但內存並沒有被清理乾淨;
比如:(示例僞代碼,不追求可運行)
class Student{
private:
    int a;
    int b;
}

class Person{

}

void main()
{
    Student* pStu = new Student;
    Person* pPer = (Person*)pStu;
    delete pPer;
}
3.申請時使用 new[],但釋放時使用 delete;

破解之道:
(new -- delete)
(new[] -- delete [])
4.比較不好排查的一種情況
示例,僞代碼,不追求可運行性
class Base{
    int a;
}

class Person:public Base{
    int b;
}

void main()
{
    Base* p = new Person;

    delete p;
}

簡單分析:
Person繼承Base基類,所以Person內存中至少存在8字節(int a + int b),
而Base* p = new Person;是合法的,
delete p;也是合法的,
問題在於 delete p 時,只釋放了Base中的資源,也就是(int a)資源,
導致派生類中(int b)資源意外丟失。


解決方法:
使用 虛析構函數

class Base{
public:
    virtual ~Base();
    int a;
}

class Person:public Base{
public:
    virtual ~Person();
    int b;
}
5.比較少見的情況
示例:僞代碼,不追求可運行性

class Test{
void* p = new char[32];
}

void main()
{
    Test a,b;
    memcpy(&a,&b,sizeof(a));
}

簡單分析:
memcpy(&a,&b,sizeof(a));
首先要知道 Test.p 也是4字節的數據塊,只不過這裏存放的是另一塊內存的起始地址,
由於完全拷貝,導致指針 a.p = b.p ,
也就是說原先 a.p 中存放的地址被 b.p 地址覆蓋,
使得原先 a.p 所指向的內存無法再被訪問到;


破解之道:
當然是禁止對類實例進行memcpy,memset這類操作啦!
6.更稀少的情況:析構函數中拋出異常導致內存泄漏

class Test{
...
    ~Test()
    {
        ...todo    //假設因爲某些條件,這裏拋出異常了
        ...todo
    }
}

調用:
std::vector<Test> vTest;

簡單分析:
vTest容器對象被銷燬之前,會先銷燬內部的Test對象實例,但Test析構函數在執行過程中,
因爲某些原因,拋出異常,導致內存未被完全釋放,甚至會引發程序後續一系列不明確行爲;

破解之道:
不要在析構函數中拋出異常,
如果出現異常,可考慮使用std::abort強制中斷程序,
更仁道的做法,是捕捉異常,但可能會有不良的運行後果,
具體如何抉擇,視情況而定,
但是,但是,但是,最好的方法,當然是禁止在析構函數中拋出異常;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章