從C語(yǔ)言開(kāi)始接觸C++的人,恐怕都知道exit()這個(gè)函數(shù),似乎現(xiàn)在很多的程序員都有這樣一種習(xí)慣,在程序一遇到錯(cuò)誤、或任務(wù)剛完成時(shí),把調(diào)用exit()函數(shù)當(dāng)成是一種的結(jié)束程序的方法。在以前遺留的許多老式C/C++代碼中,這種現(xiàn)象非常普遍,但當(dāng)手頭的軟件項(xiàng)目逐步進(jìn)展并越來(lái)越大時(shí),就不得不面臨合并以前分散的各個(gè)模塊這項(xiàng)工作,此時(shí),如果還有人記得起軟件日志記錄、錯(cuò)誤寬容度、或至少適當(dāng)?shù)那謇砉ぷ?,就已?jīng)是萬(wàn)幸了。本文中要說(shuō)的方法,決不是一條設(shè)計(jì)準(zhǔn)則,但是可減輕修正那些未良好設(shè)計(jì)及實(shí)現(xiàn)的老式代碼時(shí)所帶來(lái)的痛苦。
用return來(lái)取代exit,無(wú)疑是解決此問(wèn)題最顯而易見(jiàn)的方法,如果軟件項(xiàng)目非常簡(jiǎn)單,這也是效的解決方案;然而,項(xiàng)目中經(jīng)常有成打的函數(shù)分布在多個(gè)源文件中,且這些函數(shù)的調(diào)用也嵌套在很深的層次中,那么,事情就變得棘手了。如果在這種情況中,所有的函數(shù)都返回void,還是有可能修改它們,讓其返回一個(gè)退出碼(exit code)的,但所付出的代價(jià)也很大;如果函數(shù)已經(jīng)能返回一個(gè)有意義的值,只是在遇到錯(cuò)誤時(shí),調(diào)用了exit(),那么這項(xiàng)工作會(huì)變得更消耗時(shí)間,也會(huì)更加容易出錯(cuò)。這里說(shuō)點(diǎn)題外話,使用exit()也是有可取之處的,當(dāng)老式代碼沒(méi)有設(shè)計(jì)返回任何東西時(shí),如果想得到返回碼(return code),只有靠exit()了。
有關(guān)此問(wèn)題,還是有一個(gè)解決方法的,在這種情況下,我們假定所有的源代碼已經(jīng)為C++格式,或無(wú)需全部編譯就可以移植為C++格式,把所有exit出現(xiàn)的地方全部換成throw(這可以自動(dòng)完成,甚至無(wú)須理解老代碼是怎樣工作的);接著,在任何適當(dāng)?shù)牡胤?,捕捉為整?shù)的異常碼,這種方法還可依據(jù)嚴(yán)重性或恢復(fù)程度的不同,在不同層面上處理錯(cuò)誤。
請(qǐng)看以下示例,原始代碼如下:
// main.cpp
void main() {
//初始化
...
ProcessMail(...);
}
//另一個(gè)源文件
void ProcessMail(...) {
//初始化
...
if ( initializationError ) {
printf("faild to init!!!\n");
exit(-1);
}
while ( !shutdown ) {
ReadMail(...)
//繼續(xù)處理
...
}
}
void ReadMail(...)
{
...
//對(duì)ReadBytes()的調(diào)用出現(xiàn)在函數(shù)內(nèi)的多處地方,包括在循環(huán)中。
nBytesAvailable = ReadBytes(...)
...
}
//另一個(gè)源文件
int ReadBytes(...)
{
//讀取數(shù)據(jù)
...
if ( error ) {
printf("there was an error!!\n");
exit(-1);
}
return nBytesRead;
}
用return來(lái)取代exit,無(wú)疑是解決此問(wèn)題最顯而易見(jiàn)的方法,如果軟件項(xiàng)目非常簡(jiǎn)單,這也是效的解決方案;然而,項(xiàng)目中經(jīng)常有成打的函數(shù)分布在多個(gè)源文件中,且這些函數(shù)的調(diào)用也嵌套在很深的層次中,那么,事情就變得棘手了。如果在這種情況中,所有的函數(shù)都返回void,還是有可能修改它們,讓其返回一個(gè)退出碼(exit code)的,但所付出的代價(jià)也很大;如果函數(shù)已經(jīng)能返回一個(gè)有意義的值,只是在遇到錯(cuò)誤時(shí),調(diào)用了exit(),那么這項(xiàng)工作會(huì)變得更消耗時(shí)間,也會(huì)更加容易出錯(cuò)。這里說(shuō)點(diǎn)題外話,使用exit()也是有可取之處的,當(dāng)老式代碼沒(méi)有設(shè)計(jì)返回任何東西時(shí),如果想得到返回碼(return code),只有靠exit()了。
有關(guān)此問(wèn)題,還是有一個(gè)解決方法的,在這種情況下,我們假定所有的源代碼已經(jīng)為C++格式,或無(wú)需全部編譯就可以移植為C++格式,把所有exit出現(xiàn)的地方全部換成throw(這可以自動(dòng)完成,甚至無(wú)須理解老代碼是怎樣工作的);接著,在任何適當(dāng)?shù)牡胤?,捕捉為整?shù)的異常碼,這種方法還可依據(jù)嚴(yán)重性或恢復(fù)程度的不同,在不同層面上處理錯(cuò)誤。
請(qǐng)看以下示例,原始代碼如下:
// main.cpp
void main() {
//初始化
...
ProcessMail(...);
}
//另一個(gè)源文件
void ProcessMail(...) {
//初始化
...
if ( initializationError ) {
printf("faild to init!!!\n");
exit(-1);
}
while ( !shutdown ) {
ReadMail(...)
//繼續(xù)處理
...
}
}
void ReadMail(...)
{
...
//對(duì)ReadBytes()的調(diào)用出現(xiàn)在函數(shù)內(nèi)的多處地方,包括在循環(huán)中。
nBytesAvailable = ReadBytes(...)
...
}
//另一個(gè)源文件
int ReadBytes(...)
{
//讀取數(shù)據(jù)
...
if ( error ) {
printf("there was an error!!\n");
exit(-1);
}
return nBytesRead;
}