c++ Virtual關鍵字在類構造、析構函數使用與內存泄漏

1、virtual與構造、析構函數

  • 使用原則:類的構造函數不能是virtual函數,而類的析構函數可以且在類的繼承中基類的析構函數通常必須爲虛函數。
  • 基類的的析構函數不是虛函數的話,刪除指針時,只有該類的內存被釋放,派生類的沒有,這樣就內存泄漏了。
  • 原因分析:
    • 類的構造函數不能是虛函數:通俗地理解構造函數的作用就是爲當前類創建對應的對象,如果爲虛函數,則創建的不能爲當前類創建對象,違背了構造函數的原則。
    • 類的析構函數可以是虛函數:理論上,由於類的析構函數爲虛函數是合理的。而且,在繼承層級的具體實現中,一般都是用父類的指針指向子類對象,那麼如果基類的析構函數是虛函數,在delete 基類指針時,會調用子類的析構函數並釋放該子類對象所佔空間;而基類的析構函數不是虛函數,則並不會調用子類的析構函數,造成內存泄漏。下面爲例子:
  • 代碼實例:
#include<iostream>
using namespace std;
class ClxBase
{
public:
	ClxBase() {};
	virtual ~ClxBase() {};
	virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
}; class ClxDerived : public ClxBase
{
public:
	ClxDerived() {};
	~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
	void DoSomething() override{ cout << "Do something in class ClxDerived!" << endl; };
};


int main()
{
	ClxBase *pTest = new ClxDerived;
	pTest->DoSomething();
	delete pTest;

	system("pause");
	return 0;
}
  • 運行結果
    在這裏插入圖片描述
    而基類的析構函數不是虛函數運行結果如下,可見子類的析構函數並沒用調用!
    在這裏插入圖片描述
  • 實例代碼注意
    • 一般用new關鍵字創建的對象一定要使用delete關鍵字進行釋放。注意new 時會調用構造函數對創建的對象進行初始化,delete時會調用析構函數進行釋放對象前的清理工作。注意,析構函數的作用並不是刪除對象,而是在撤銷對象佔用的內存之前完成一些清理工作;同理構造函數也不是創建對象,而是對創建的對象進行一些初始化工作。

2、內存泄漏

  • 既然上面內容涉及到了內存泄漏的知識則在這裏總結下c++內存泄漏的幾種情況。
  • 1、沒有匹配地使用new、delete。因爲使用new則是在堆上創建的內存,需要用戶手動釋放。(延申:非new形式定義的對象在進程虛擬地址空間的棧地址上存儲,new申請的空間在堆上創建。兩種創建位置主要區別:1.空間大小 2、是否由系統自動回收3、創建速度)
  • 2、使用delete釋放指向對象數組的指針時沒有加[]。主要這裏的對象指的時自定義的類對象,簡單的基本數據類型對象不加[]也可以。其原因是如果沒有方括號,那麼這個指針就被默認爲只指向一個對象,對象數組中的其他對象的析構函數就不會被調用,結果造成了內存泄露;而基本類型系統記憶其空間大小,無需調用構造函數。
  • 3、基類的析構函數不是虛函數。(當基類指針指向子類對象時,如果基類的析構函數不是virtual,那麼子類的析構函數將不會被調用,子類的資源沒有正確是釋放,因此造成內存泄露)
  • 4、缺少拷貝構造函數。如果沒有定義拷貝構造函數,那麼編譯器就會調用默認的拷貝構造函數,會逐個成員拷貝的方式來複制數據成員,如果是以逐個成員拷貝的方式來複制指針被定義爲將一個變量的地址賦給另一個變量。這種隱式的指針複製結果就是兩個對象擁有指向同一個動態分配的內存空間的指針。當釋放第一個對象的時候,它的析構函數就會釋放與該對象有關的動態分配的內存空間。而釋放第二個對象的時候,它的析構函數會釋放相同的內存,這樣是錯誤的。
  • 5、缺少賦值構造函數。原理與拷貝構造函數相同。
  • 6、對象指針數組的釋放與對象數組的釋放不同。(數組中存放的是指向對象的指針,不僅要釋放每個對象的空間,還要釋放每個指針的空間,delete []p只是釋放了每個指針,但是並沒有釋放對象的空間,正確的做法,是通過一個循環,將每個對象釋放了,然後再把指針釋放了。)

3、野指針出現情況

  • 1、定義指針沒賦值NULL;
  • 2、指針越界訪問
  • 3、delete ptr指針後,沒有將NULL賦值給ptr。因爲delete只是刪除了ptr指向的內存空間,並不是刪除了ptr指針。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章