記憶體洩露及其解決之道

2021-04-26 06:25:34 字數 4647 閱讀 8113

前言:此文甚好,權作時時複習之用。原文出處:

本人改正了一些錯別字。

正文:記憶體洩露及其解決之道

new/delete, array new/arrray delete匹配

case 1:

在類的建構函式與析構函式中沒有匹配地呼叫 new/delete! 解決方法:檢查建構函式,在出現new的情況下,按相反的順序在析構函式中匹配新增delete!

這裡有兩個意思:

1〉new與delete匹配,array new/array delete匹配;

2〉出現在前面的new要比出現在後面的new後匹配各自的delete;

比如:

建構函式:

m_x = new int[10];

...

m_y = new cstring;

則析構函式:

delete m_y;

...

delete m_x; // 對於基本資料型別,用delete也可以,但為了統一,還      // 是用array delete ­

case 2:

沒有正確地清除巢狀的物件指標

也就是說,某個物件以引用語義(指標)了包含另乙個物件,而不是以值的方式。

解決辦法:

1〉養成好的成對編碼習慣:

在外部函式分配的堆記憶體,不要在呼叫函式裡面釋放,而在外部函式內釋放;

2〉盡量在建構函式裡面分配記憶體,並注意不要犯case 1錯誤;

3〉在基類/繼承類各管各的記憶體;(具體解析見下面的case 8)

for example:

#include

#include

// melon : 甜瓜,西瓜;

class melon ;

melon::melon(char * var)

melon::~melon()

void melon::print()

// meal : 進餐;

class meal ;

meal::meal(char * var, char * res)

// 方法2:改引用為值包含;

// : m_melon(var)

meal::~meal()

void meal::print()

int main(...)

case 3:在釋放物件陣列時,沒有使用delete ;

1>對於單個物件,單個基本型別(如int,double等)的變數,我們肯定採用delete,不會出錯;

2>對於基本型別陣列,由於不需要大小引數,因而,採用delete或array delete(delete ),均可以,如上例中,我便直接採用了delete m_variety,建議為了統一,採用delete m_variety;

3>對於自定義的物件所組成的物件陣列,則一定要採用array delete,這樣編譯器才會在釋放記憶體前呼叫每個物件的析構函式,並呼叫

free釋放物件陣列空間;

for example:

#include

#include

class point ;

point::point(int x, int y, char *col)

: m_x(x), m_y(y)

point::~point()

int main(int argc, char *argv)

case 4:

指向由指向物件的指標構成的陣列不等同於與物件陣列。

也就是說,陣列的基本型別是指向物件的指標,此時,是用delete 還是delete (array delete),並不重要,關鍵是指標並沒有析構函式,必須使用者自己呼叫delete語句.

for example:

// point類和case 3一樣;

int main(int argc, char *argv)

// 下面語句並沒有釋放10個point物件,釋放的只是他們的指標所組成的陣列

// 占用的10*sizeof(point*) 空間,造成了記憶體洩露

// (180 = 10*sizeof(point) + 10* 6; (6= sizeof("green")))

// delete pptrary;

// 正確的方法:

for (i = 0; i < 10; ++i)

delete pptrary; // 或者delete pptrary;

return 0; }

case 5:

缺少拷貝建構函式

這沒什麼好說的,主要是解決編譯器預設新增的拷貝建構函式不足!預設的拷貝建構函式採用位拷貝,

如下**:

point x;

point y(x);

這樣會導致兩個point物件 x,y的 m_color指向同乙個"red"字串;

當某個物件釋放後,另外乙個物件的 m_color變成懸空指標,從而導致程式異常;

解決方法:

編寫自己的拷貝建構函式;

對於point類,編寫如下:

point::point(const point& y)

: m_x(y.m_x), m_y(y.m_y)

case 6:

缺少過載賦值運算子,理由和上面一樣!

需要注意其實現的細節區別:

1> 拷貝建構函式編譯器會自動阻止自己構造自己,比如:

point x(x); // 出錯;

但是,賦值操作不會;

point x = x; // 編譯期不會出錯,但執行期會出錯!

上面的錯誤原因在於,編譯器雖然為x分配了記憶體,但呼叫拷貝建構函式時,m_color還沒初始化;

建議,盡量不要用這種方法初始化,以便將錯誤在編譯期間顯示出來;

2> 賦值運算子必須區別是否自身賦值;

3> 在賦值前必須釋放原有new操作分配的資源(當然,其他檔案等資源也要釋放,這裡只討論記憶體溢位,略過不提!)

最後實現如下:

const point& point::operator =(const point& rhs)

return *this; }

注意,最左邊的const宣告可以不要,要得話是為了阻止如下語句:

(x = y) = z;

但由於基本型別也支援,為了與基本型別一致,可以去掉const約束;

case 7:

關於nonmodifying運算子過載的常見錯誤;

所謂nonmodifying運算子就是不改變運算元的值,並且返回結果型別與運算元一樣;比如數**算符;

而關係運算子則不滿足,因為其結果為bool型;

賦值運算子也不是(=, += ,<<=等等);

主要原因是,大家可能將結果儲存到乙個區域性變數裡面,而返回結果為了效率採用了引用(&);

解決方法:

1> 利用static, 將臨時變數作為類的內部儲存單元;

不足,不適合巢狀使用和多執行緒,比如 w = x+y+z;

for example:

// case 7,解決方法1:static

const point& point::operator +(const point& rhs) const

注意,這裡為了簡單,並沒有考慮型別轉換,實際中二元運算子通常採用友元函式形式實現,具體判斷方法請看effective c++ item 19;

2> 改引用語義為值語義;(最好辦法,但會降低效率)

注意,有人也許會用指標方法,比如如下:

point *temp = new point;

...

return (*temp);

這樣會產生乙個無名物件,並且位於堆上,從而造成記憶體洩露;

const point point::operator +(const point& rhs) const

case 8:

沒用將基類的析構函式定義成虛函式;

解決方法:

將基類的析構函式定義為虛函式;

這種情況主要出現在下面情況:

基類指標指向派生類;

for example:

so someone write such codes: ­

fruit *basket[20];

for (int i = 0; i < 10; ++i)

­for (; i < 20; ++i)

for (i = 0; i < 20; ++i)

具體實現略!

注意:

1> 該錯誤具有隱蔽性,當所有派生類均沒有新的new操作時,不會產生記憶體溢位;因而,最好遵循以下原則:

將基類建構函式定義為非虛函式,則該類不允許擴充套件;

2> 如果不是虛函式,則釋放基類指標不會呼叫派生類的析構函式,即使它指向乙個派生類物件;

3> 不管是不是虛函式,釋放派生類指標均會呼叫基類的析構函式,且呼叫順序不變;

4> 如果為虛函式,則釋放基類指標且該指標指向乙個派生類,則會先呼叫派生類的析構函式,再呼叫基內的析構函式!

亂碼解決之道

一.jsp頁面讀取資料庫資料 確認資料庫的資料不是亂碼 mysql建庫建表時設定統一的字符集 jsp頁面編碼設定支援中文,這時jsp頁面可以正常顯示中文。二.從jsp提交資料到資料庫 從jsp頁面的中文提交到action或者servlet後,要重新設定編碼 new string param.getb...

工控安全解決之道

工控安全解決之道 首先,筆者先說明一下關於安全的三個概念 第一,安全不免費 第二,安全的最高境界是感覺不到安全 第三,安全無僥倖。第乙個概念,安全不免費,這個概念很好理解,世上沒有白吃的午餐,企業要想做安全就要做好投入的準備,這個概念誰都同意,但是很多人就未必願意做。為什麼呢?他會說以前我沒做安全也...

微軟虛擬化解決之道

隨著計算機硬體運算能力的突飛猛進,使虛擬化應用成為理由當然的事情,這是降低資訊化建設tco的有效手段之一。微軟 vmware等都是虛擬化應用行業的大拿,引領著虛擬化技術的發展方向。vmware在伺服器的虛擬化應用方面有獨到之處,微軟則在虛擬化整合以及提供一攬子虛擬化解決方案等方面領先。對於企業的虛擬...