C++实用技巧(二)
生活随笔
收集整理的這篇文章主要介紹了
C++实用技巧(二)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
復(fù)雜的東西寫多了,如今寫點(diǎn)簡(jiǎn)單的好了。由于功能上的需要,
Vczh Library++3.0
被我搞得很離譜。為了開發(fā)維護(hù)的遍歷、減少粗心犯下的錯(cuò)誤以及增強(qiáng)單元測(cè)試、回歸測(cè)試和測(cè)試工具,因此記錄下一些開發(fā)上的小技巧,以便拋磚引玉,造福他人。歡迎高手來(lái)噴,菜鳥膜拜。
???? 上一篇文章 講到了如何檢查內(nèi)存泄露。其實(shí)只要肯用C++的STL里面的高級(jí)功能的話,內(nèi)存泄露是很容易避免的。我在開發(fā)Vczh Library++ 3.0的時(shí)候,所有的測(cè)試用例都保證跑完了沒(méi)有內(nèi)存泄露。但是很可惜有些C++團(tuán)隊(duì)不能使用異常,更甚者不允許寫構(gòu)造函數(shù)析構(gòu)函數(shù)之類,前一個(gè)還好,后一個(gè)簡(jiǎn)直就是在用C。當(dāng)然有這些變態(tài)規(guī)定的地方STL都是用不了的,所以我們更加需要扎實(shí)的基礎(chǔ)來(lái)開發(fā)C++程序。
??? 今天這一篇主要還是講指針的問(wèn)題。因?yàn)樯弦黄恼乱还P帶過(guò),今天就來(lái)詳細(xì)講內(nèi)存泄漏或者野指針發(fā)生的各種情況。當(dāng)然我不可能一下子舉出全部的例子,只能說(shuō)一些常見的。
???? 一、錯(cuò)誤覆蓋內(nèi)存。
??? 之前提到的不能隨便亂memset其實(shí)就是為了避免這個(gè)問(wèn)題的。其實(shí)memcpy也不能亂用,我們來(lái)看一個(gè)例子,最簡(jiǎn)單的:
?1?#define?MAX_STRING?20;
?2?
?3?struct?Student
?4?{
?5???char?name[MAX_STRING];
?6???char?id[MAX_STRING];
?7???int?chinese;
?8???int?math;
?9???int?english;
10?};
??? 大家對(duì)這種結(jié)構(gòu)肯定十分熟悉,畢竟是大學(xué)時(shí)候經(jīng)常要寫的作業(yè)題……好了,大家很容易看得出來(lái)這其實(shí)是C語(yǔ)言的經(jīng)典寫法。我們拿到手之后,一般會(huì)先初始化一下,然后賦值。
1?Student?vczh;
2?memset(&vczh,?0,?sizeof(vczh));
3?strcpy(vczh.name,?"vczh");
4?strcpy(vczh.id,?"VCZH'S?ID");
5?vczh.chinese=70;
6?vczh.math=90;
7?vczh.english=80;
??? 為什么要在這里使用memset呢?memset的用處是將一段內(nèi)存的每一個(gè)字節(jié)都設(shè)置成同一個(gè)數(shù)字。這里是0,因此兩個(gè)字符串成員的所有字節(jié)都會(huì)變成0。因此在memset了Student之后,我們通過(guò)正常方法來(lái)訪問(wèn)name和id的時(shí)候都會(huì)得到空串。而且如果Student里面有指針的話,0指針代表的是沒(méi)有指向任何有效對(duì)象,因此這個(gè)時(shí)候?qū)χ羔樦赶虻膶?duì)象進(jìn)行讀寫就會(huì)立刻崩潰。對(duì)于其他數(shù)值,0一般作為初始值也不會(huì)有什么問(wèn)題(double什么的要小心)。這就是我們寫程序的時(shí)候使用memset的原因。
??? 好了,如今社會(huì)進(jìn)步,人民當(dāng)家做主了,死程們?cè)僖膊恍枰艿娇蓯旱腃語(yǔ)言剝削了,我們可以使用C++!因此我們借助STL的力量把Student改寫成下面這種帶有C++味道的形式:
1?struct?Student
2?{
3???std::string?name;
4???std::string?id;
5???int?chinese;
6???int?math;
7???int?english;
8?};
??? 我們?nèi)匀恍枰獙?duì)Student進(jìn)行初始化,不然三個(gè)分?jǐn)?shù)還是隨機(jī)值。但是我們又不想每一次創(chuàng)建的時(shí)候都對(duì)他們分別進(jìn)行賦值初始化城0。這個(gè)時(shí)候你心里可能還是想著memset, 這就錯(cuò)了 !在memset的時(shí)候,你會(huì)把std::string內(nèi)部的不知道什么東西也給memset掉。假如一個(gè)空的std::string里面存放的指針指向的是一個(gè)空的字符串而不是用0來(lái)代表空的時(shí)候,一下子內(nèi)部的指針就被你刷成0,等下std::string的析構(gòu)函數(shù)就沒(méi)辦法delete掉指針了,于是 內(nèi)存泄露就出現(xiàn)了 。有些朋友可能不知道上面那句話說(shuō)的是什么意思,我們現(xiàn)在來(lái)模擬一下不能memset的std::string要怎么實(shí)現(xiàn)。
??? 為了讓memset一定出現(xiàn)內(nèi)存泄露,那么std::string里面的指針必須永遠(yuǎn)都指向一個(gè)有效的東西。當(dāng)然我們還需要在字符串進(jìn)行復(fù)制的時(shí)候復(fù)制指針。我們這里不考慮各種優(yōu)化技術(shù),用最簡(jiǎn)單的方法做一個(gè)字符串出來(lái):
?1?class?String
?2?{
?3?private:
?4???char*?buffer;
?5?
?6?public:
?7???String()
?8???{
?9?????buffer=new?char[1];
10?????buffer[0]=0;
11???}
12?
13???String(const?char*?s)
14???{
15?????buffer=new?char[strlen(s)+1];
16?????strcpy(buffer,?s);
17???}
18?
19???String(const?String&?s)
20???{
21?????buffer=new?char[strlen(s.buffer)+1];
22?????strcpy(buffer,?s.buffer);
23???}
24?
25???~String()
26???{
27?????delete[]?buffer;
28???}
29?
30???String&?operator=(const?String&?s)
31???{
32?????delete[]?buffer;
33?????buffer=new?char[strlen(s.buffer)+1];
34?????strcpy(buffer,?s.buffer);
35???}
36?};
??? 于是我們來(lái)做一下memset。首先定義一個(gè)字符串變量,其次memset掉,讓我們看看會(huì)發(fā)生什么事情:
1?string?s;
2?memset(&s,?0,?sizeof(s));
??? 第一行我們構(gòu)造了一個(gè)字符串s。這個(gè)時(shí)候字符串的構(gòu)造函數(shù)就會(huì)開始運(yùn)行,因此strcmp(s.buffer, "")==0。第二行我們把那個(gè)字符串給memset掉了。這個(gè)時(shí)候s.buffer==0。于是函數(shù)結(jié)束了,字符串的析構(gòu)函數(shù)嘗試delete這個(gè)指針。我們知道delete一個(gè)0是不會(huì)有問(wèn)題的,因此程序不會(huì)發(fā)生錯(cuò)誤。 我們活生生把構(gòu)造函數(shù)賦值給buffer的new char[1]給丟了 !鐵定發(fā)生內(nèi)存泄露!
??? 好了,提出問(wèn)題總要解決問(wèn)題,我們不使用memset的話,怎么初始化Student呢?這個(gè)十分好做,我們只需要為Student加上構(gòu)造函數(shù)即可:
1?struct?Student
2?{
3???.//不重復(fù)那些聲明
4?
5???Student():chinese(0),math(0),english(0)
6???{
7???}
8?};
??? 這樣就容易多了。每當(dāng)我們定義一個(gè)Student變量的時(shí)候,所有的成員都初始化好了。name和id因?yàn)閟tring的構(gòu)造函數(shù)也自己初始化了,因此所有的成員也都初始化了。加入Student用了一半我們想再初始化一下怎么辦呢?也很容易:
1?Student?vczh;
2?.//各種使用
3?vczh=Student();
??? 經(jīng)過(guò)一個(gè)等號(hào)操作符的調(diào)用,舊Student的所有成員就被一個(gè)新的初始化過(guò)的Student給覆蓋了,就如同我們對(duì)一個(gè)int變量重新賦值一樣常見。當(dāng)然因?yàn)楦鞣N復(fù)制經(jīng)常會(huì)出現(xiàn),因此我們也要跟上面貼出來(lái)的string的例子一樣,實(shí)現(xiàn)好那4個(gè)函數(shù)。至此我十分不理解為什么某些團(tuán)隊(duì)不允許使用構(gòu)造函數(shù),我猜就是為了可以memset,其實(shí)是很沒(méi)道理的。
???? 二、異常。
??? 咋一看內(nèi)存泄露跟異常好像沒(méi)什么關(guān)系,但實(shí)際上這種情況更容易發(fā)生。我們來(lái)看一個(gè)例子:
?1?char*?strA=new?char[MAX_PATH];
?2?if(GetXXX(strA,?MAX_PATH)==ERROR)?goto?RELEASE_STRA;
?3?char*?strB=new?char[MAX_PATH];
?4?if(GetXXX(strB,?MAX_PATH)==ERROR)?goto?RELEASE_STRB;
?5?
?6?DoSomething(strA,?strB);
?7?
?8?RELEASE_STRB:
?9?delete[]?strB;
10?RELEASE_STRA:
11?delete[]?strA;
??? 相信這肯定是大家的常用模式。我在這里也不是教唆大家使用goto,不過(guò)對(duì)于這種例子來(lái)說(shuō),用goto是最優(yōu)美的解決辦法了。但是大家可以看出來(lái),我們用的是C++,因?yàn)檫@里有new。如果DoSomething發(fā)生了異常怎么辦呢?如果GetXXX發(fā)生了異常怎么辦呢?我們這里沒(méi)有任何的try-catch,一有異常,函數(shù)里克結(jié)束,兩行可憐的delete就不會(huì)被執(zhí)行到了, 于是內(nèi)存泄漏發(fā)生了 !
??? 那我們?nèi)绾伪苊膺@種情況下的內(nèi)存泄露呢?一些可愛(ài)的小盆友可能會(huì)想到,既然是因?yàn)闆](méi)有catch異常才發(fā)生的內(nèi)存泄露,那我們來(lái)catch吧:
?1?char*?strA=new?char[MAX_PATH];
?2?try
?3?{
?4???if(GetXXX(strA,?MAX_PATH)==ERROR)?goto?RELEASE_STRA;
?5???char*?strB=new?char[MAX_PATH];
?6???try
?7???{
?8?????if(GetXXX(strB,?MAX_PATH)==ERROR)?goto?RELEASE_STRB;
?9?????DoSomething(strA,?strB);
10???}
11???catch()
12???{
13?????delete[]?strB;
14?????throw;
15???}
16?}
17?catch()
18?{
19???delete[]?strA;
20???throw;
21?}
22?
23?RELEASE_STRB:
24?delete[]?strB;
25?RELEASE_STRA:
26?delete[]?strA;
??? 你能接受嗎?當(dāng)然是不能的。問(wèn)題出在哪里呢?因?yàn)镃++沒(méi)有try-finally。你看這些代碼到處都是雷同的東西,顯然我們需要編譯器幫我們把這些問(wèn)題搞定。最好的解決方法是什么呢?顯然還是構(gòu)造函數(shù)和析構(gòu)函數(shù)。總之記住, 如果想要事情成對(duì)發(fā)生,那么使用構(gòu)造函數(shù)和析構(gòu)函數(shù) 。
??? 第一步,GetXXX顯然只能支持C模式的東西,因此我們要寫一個(gè)支持C++的:
?1?bool?GetXXX2(string&?s)
?2?{
?3???char*?str=new?char[MAX_PATH];
?4???bool?result;
?5???try
?6???{
?7?????result=GetXXX(str,?MAX_PATH);
?8?????if(result)s=str;
?9???}
10???catch()
11???{
12?????delete[]?str;
13?????throw;
14???}
15???delete[]?str;
16???return?result;
17?}
??? 借助這個(gè)函數(shù)我們可以看到,因?yàn)橛辛薌etXXX這種C的東西,導(dǎo)致我們多了多少麻煩。不過(guò)這總是一勞永逸的,有了GetXXX2和修改之后的DoSomething2之后,我們就可以用更簡(jiǎn)單的方法來(lái)做了:
1?string?a,b;
2?if(GetXXX2(a)?&&?GetXXX2(b))
3?{
4???DoSomething2(a,?b);
5?}
??? 多么簡(jiǎn)單易懂。這個(gè)代碼在任何地方發(fā)生了異常,所有new的東西都會(huì)被delete。這就是析構(gòu)函數(shù)的一個(gè)好處。一個(gè)變量的析構(gòu)函數(shù)在這個(gè)變量超出了作用域的時(shí)候一定會(huì)被調(diào)用,無(wú)論代碼是怎么走出去的。
???? 上一篇文章 講到了如何檢查內(nèi)存泄露。其實(shí)只要肯用C++的STL里面的高級(jí)功能的話,內(nèi)存泄露是很容易避免的。我在開發(fā)Vczh Library++ 3.0的時(shí)候,所有的測(cè)試用例都保證跑完了沒(méi)有內(nèi)存泄露。但是很可惜有些C++團(tuán)隊(duì)不能使用異常,更甚者不允許寫構(gòu)造函數(shù)析構(gòu)函數(shù)之類,前一個(gè)還好,后一個(gè)簡(jiǎn)直就是在用C。當(dāng)然有這些變態(tài)規(guī)定的地方STL都是用不了的,所以我們更加需要扎實(shí)的基礎(chǔ)來(lái)開發(fā)C++程序。
??? 今天這一篇主要還是講指針的問(wèn)題。因?yàn)樯弦黄恼乱还P帶過(guò),今天就來(lái)詳細(xì)講內(nèi)存泄漏或者野指針發(fā)生的各種情況。當(dāng)然我不可能一下子舉出全部的例子,只能說(shuō)一些常見的。
???? 一、錯(cuò)誤覆蓋內(nèi)存。
??? 之前提到的不能隨便亂memset其實(shí)就是為了避免這個(gè)問(wèn)題的。其實(shí)memcpy也不能亂用,我們來(lái)看一個(gè)例子,最簡(jiǎn)單的:
?1?#define?MAX_STRING?20;
?2?
?3?struct?Student
?4?{
?5???char?name[MAX_STRING];
?6???char?id[MAX_STRING];
?7???int?chinese;
?8???int?math;
?9???int?english;
10?};
??? 大家對(duì)這種結(jié)構(gòu)肯定十分熟悉,畢竟是大學(xué)時(shí)候經(jīng)常要寫的作業(yè)題……好了,大家很容易看得出來(lái)這其實(shí)是C語(yǔ)言的經(jīng)典寫法。我們拿到手之后,一般會(huì)先初始化一下,然后賦值。
1?Student?vczh;
2?memset(&vczh,?0,?sizeof(vczh));
3?strcpy(vczh.name,?"vczh");
4?strcpy(vczh.id,?"VCZH'S?ID");
5?vczh.chinese=70;
6?vczh.math=90;
7?vczh.english=80;
??? 為什么要在這里使用memset呢?memset的用處是將一段內(nèi)存的每一個(gè)字節(jié)都設(shè)置成同一個(gè)數(shù)字。這里是0,因此兩個(gè)字符串成員的所有字節(jié)都會(huì)變成0。因此在memset了Student之后,我們通過(guò)正常方法來(lái)訪問(wèn)name和id的時(shí)候都會(huì)得到空串。而且如果Student里面有指針的話,0指針代表的是沒(méi)有指向任何有效對(duì)象,因此這個(gè)時(shí)候?qū)χ羔樦赶虻膶?duì)象進(jìn)行讀寫就會(huì)立刻崩潰。對(duì)于其他數(shù)值,0一般作為初始值也不會(huì)有什么問(wèn)題(double什么的要小心)。這就是我們寫程序的時(shí)候使用memset的原因。
??? 好了,如今社會(huì)進(jìn)步,人民當(dāng)家做主了,死程們?cè)僖膊恍枰艿娇蓯旱腃語(yǔ)言剝削了,我們可以使用C++!因此我們借助STL的力量把Student改寫成下面這種帶有C++味道的形式:
1?struct?Student
2?{
3???std::string?name;
4???std::string?id;
5???int?chinese;
6???int?math;
7???int?english;
8?};
??? 我們?nèi)匀恍枰獙?duì)Student進(jìn)行初始化,不然三個(gè)分?jǐn)?shù)還是隨機(jī)值。但是我們又不想每一次創(chuàng)建的時(shí)候都對(duì)他們分別進(jìn)行賦值初始化城0。這個(gè)時(shí)候你心里可能還是想著memset, 這就錯(cuò)了 !在memset的時(shí)候,你會(huì)把std::string內(nèi)部的不知道什么東西也給memset掉。假如一個(gè)空的std::string里面存放的指針指向的是一個(gè)空的字符串而不是用0來(lái)代表空的時(shí)候,一下子內(nèi)部的指針就被你刷成0,等下std::string的析構(gòu)函數(shù)就沒(méi)辦法delete掉指針了,于是 內(nèi)存泄露就出現(xiàn)了 。有些朋友可能不知道上面那句話說(shuō)的是什么意思,我們現(xiàn)在來(lái)模擬一下不能memset的std::string要怎么實(shí)現(xiàn)。
??? 為了讓memset一定出現(xiàn)內(nèi)存泄露,那么std::string里面的指針必須永遠(yuǎn)都指向一個(gè)有效的東西。當(dāng)然我們還需要在字符串進(jìn)行復(fù)制的時(shí)候復(fù)制指針。我們這里不考慮各種優(yōu)化技術(shù),用最簡(jiǎn)單的方法做一個(gè)字符串出來(lái):
?1?class?String
?2?{
?3?private:
?4???char*?buffer;
?5?
?6?public:
?7???String()
?8???{
?9?????buffer=new?char[1];
10?????buffer[0]=0;
11???}
12?
13???String(const?char*?s)
14???{
15?????buffer=new?char[strlen(s)+1];
16?????strcpy(buffer,?s);
17???}
18?
19???String(const?String&?s)
20???{
21?????buffer=new?char[strlen(s.buffer)+1];
22?????strcpy(buffer,?s.buffer);
23???}
24?
25???~String()
26???{
27?????delete[]?buffer;
28???}
29?
30???String&?operator=(const?String&?s)
31???{
32?????delete[]?buffer;
33?????buffer=new?char[strlen(s.buffer)+1];
34?????strcpy(buffer,?s.buffer);
35???}
36?};
??? 于是我們來(lái)做一下memset。首先定義一個(gè)字符串變量,其次memset掉,讓我們看看會(huì)發(fā)生什么事情:
1?string?s;
2?memset(&s,?0,?sizeof(s));
??? 第一行我們構(gòu)造了一個(gè)字符串s。這個(gè)時(shí)候字符串的構(gòu)造函數(shù)就會(huì)開始運(yùn)行,因此strcmp(s.buffer, "")==0。第二行我們把那個(gè)字符串給memset掉了。這個(gè)時(shí)候s.buffer==0。于是函數(shù)結(jié)束了,字符串的析構(gòu)函數(shù)嘗試delete這個(gè)指針。我們知道delete一個(gè)0是不會(huì)有問(wèn)題的,因此程序不會(huì)發(fā)生錯(cuò)誤。 我們活生生把構(gòu)造函數(shù)賦值給buffer的new char[1]給丟了 !鐵定發(fā)生內(nèi)存泄露!
??? 好了,提出問(wèn)題總要解決問(wèn)題,我們不使用memset的話,怎么初始化Student呢?這個(gè)十分好做,我們只需要為Student加上構(gòu)造函數(shù)即可:
1?struct?Student
2?{
3???.//不重復(fù)那些聲明
4?
5???Student():chinese(0),math(0),english(0)
6???{
7???}
8?};
??? 這樣就容易多了。每當(dāng)我們定義一個(gè)Student變量的時(shí)候,所有的成員都初始化好了。name和id因?yàn)閟tring的構(gòu)造函數(shù)也自己初始化了,因此所有的成員也都初始化了。加入Student用了一半我們想再初始化一下怎么辦呢?也很容易:
1?Student?vczh;
2?.//各種使用
3?vczh=Student();
??? 經(jīng)過(guò)一個(gè)等號(hào)操作符的調(diào)用,舊Student的所有成員就被一個(gè)新的初始化過(guò)的Student給覆蓋了,就如同我們對(duì)一個(gè)int變量重新賦值一樣常見。當(dāng)然因?yàn)楦鞣N復(fù)制經(jīng)常會(huì)出現(xiàn),因此我們也要跟上面貼出來(lái)的string的例子一樣,實(shí)現(xiàn)好那4個(gè)函數(shù)。至此我十分不理解為什么某些團(tuán)隊(duì)不允許使用構(gòu)造函數(shù),我猜就是為了可以memset,其實(shí)是很沒(méi)道理的。
???? 二、異常。
??? 咋一看內(nèi)存泄露跟異常好像沒(méi)什么關(guān)系,但實(shí)際上這種情況更容易發(fā)生。我們來(lái)看一個(gè)例子:
?1?char*?strA=new?char[MAX_PATH];
?2?if(GetXXX(strA,?MAX_PATH)==ERROR)?goto?RELEASE_STRA;
?3?char*?strB=new?char[MAX_PATH];
?4?if(GetXXX(strB,?MAX_PATH)==ERROR)?goto?RELEASE_STRB;
?5?
?6?DoSomething(strA,?strB);
?7?
?8?RELEASE_STRB:
?9?delete[]?strB;
10?RELEASE_STRA:
11?delete[]?strA;
??? 相信這肯定是大家的常用模式。我在這里也不是教唆大家使用goto,不過(guò)對(duì)于這種例子來(lái)說(shuō),用goto是最優(yōu)美的解決辦法了。但是大家可以看出來(lái),我們用的是C++,因?yàn)檫@里有new。如果DoSomething發(fā)生了異常怎么辦呢?如果GetXXX發(fā)生了異常怎么辦呢?我們這里沒(méi)有任何的try-catch,一有異常,函數(shù)里克結(jié)束,兩行可憐的delete就不會(huì)被執(zhí)行到了, 于是內(nèi)存泄漏發(fā)生了 !
??? 那我們?nèi)绾伪苊膺@種情況下的內(nèi)存泄露呢?一些可愛(ài)的小盆友可能會(huì)想到,既然是因?yàn)闆](méi)有catch異常才發(fā)生的內(nèi)存泄露,那我們來(lái)catch吧:
?1?char*?strA=new?char[MAX_PATH];
?2?try
?3?{
?4???if(GetXXX(strA,?MAX_PATH)==ERROR)?goto?RELEASE_STRA;
?5???char*?strB=new?char[MAX_PATH];
?6???try
?7???{
?8?????if(GetXXX(strB,?MAX_PATH)==ERROR)?goto?RELEASE_STRB;
?9?????DoSomething(strA,?strB);
10???}
11???catch()
12???{
13?????delete[]?strB;
14?????throw;
15???}
16?}
17?catch()
18?{
19???delete[]?strA;
20???throw;
21?}
22?
23?RELEASE_STRB:
24?delete[]?strB;
25?RELEASE_STRA:
26?delete[]?strA;
??? 你能接受嗎?當(dāng)然是不能的。問(wèn)題出在哪里呢?因?yàn)镃++沒(méi)有try-finally。你看這些代碼到處都是雷同的東西,顯然我們需要編譯器幫我們把這些問(wèn)題搞定。最好的解決方法是什么呢?顯然還是構(gòu)造函數(shù)和析構(gòu)函數(shù)。總之記住, 如果想要事情成對(duì)發(fā)生,那么使用構(gòu)造函數(shù)和析構(gòu)函數(shù) 。
??? 第一步,GetXXX顯然只能支持C模式的東西,因此我們要寫一個(gè)支持C++的:
?1?bool?GetXXX2(string&?s)
?2?{
?3???char*?str=new?char[MAX_PATH];
?4???bool?result;
?5???try
?6???{
?7?????result=GetXXX(str,?MAX_PATH);
?8?????if(result)s=str;
?9???}
10???catch()
11???{
12?????delete[]?str;
13?????throw;
14???}
15???delete[]?str;
16???return?result;
17?}
??? 借助這個(gè)函數(shù)我們可以看到,因?yàn)橛辛薌etXXX這種C的東西,導(dǎo)致我們多了多少麻煩。不過(guò)這總是一勞永逸的,有了GetXXX2和修改之后的DoSomething2之后,我們就可以用更簡(jiǎn)單的方法來(lái)做了:
1?string?a,b;
2?if(GetXXX2(a)?&&?GetXXX2(b))
3?{
4???DoSomething2(a,?b);
5?}
??? 多么簡(jiǎn)單易懂。這個(gè)代碼在任何地方發(fā)生了異常,所有new的東西都會(huì)被delete。這就是析構(gòu)函數(shù)的一個(gè)好處。一個(gè)變量的析構(gòu)函數(shù)在這個(gè)變量超出了作用域的時(shí)候一定會(huì)被調(diào)用,無(wú)論代碼是怎么走出去的。
??? 今天就說(shuō)到這里了。說(shuō)了這么多還是想讓大家不要小看構(gòu)造函數(shù)和析構(gòu)函數(shù)。那種微不足道的因?yàn)橐恍〔糠植皇瞧款i的性能問(wèn)題而放棄構(gòu)造函數(shù)和析構(gòu)函數(shù)的做法,終究是要為了修bug而加班的。只要明白并用好了構(gòu)造函數(shù)、析構(gòu)函數(shù)和異常,那么C++的特性也可以跟C一樣清楚明白便于理解,而且寫出來(lái)的代碼更好看的。大家期待第三篇哈。
from:?http://www.cppblog.com/vczh/archive/2010/06/24/118603.html
總結(jié)
以上是生活随笔為你收集整理的C++实用技巧(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C++实用技巧(一)
- 下一篇: C++实用技巧(三)