麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

Effective C++ 2e Item46

2019-09-10 09:07:18
字體:
來源:轉載
供稿:網友

條款46: 寧可編譯和鏈接時出錯,也不要運行時出錯

除了極少數情況下會使C++拋出異常(例如,內存耗盡 ---- 見條款7)外,運行時錯誤的概念和C++沒什么關系,就象在C中一樣。沒有下溢,上溢,除零檢查;沒有數組越界檢查,等等。一旦程序通過了編譯和鏈接,你就得靠自己了 ---- 一切后果自負。這很象跳傘運動,一些人從中找到了刺激,另一些人則嚇得摔成了殘廢。這一思想背后的動機當然在于效率:沒有運行時檢查,程序會更小更快。

處理這類事情有另一個不同的方法。一些語言如Smalltalk和LISP通常在編譯鏈接期間只是檢查極少一些錯誤,但卻提供了強大的運行時系統來處理執行期間的錯誤。不象C++,這些語言幾乎都是解釋型的,在提供額外靈活性的同時,它們也帶來了性能上的損失。

不要忘了你是在用C++編程。即使發現Smalltalk/LISP的方法很吸引人,也要忘掉它們。常說要堅持黨的路線,現在的情況下,它的含義就是要避免運行時錯誤。只要有可能,就要讓出錯檢查從運行時退回到鏈接時,或者,最理想的是,編譯時。

這種方法帶來的好處不僅僅在于程序的大小和速度,還有可靠性。如果程序通過了編譯和鏈接而沒有產生錯誤信息,你就可以確信程序中沒有編譯器和鏈接器能檢查得到的任何錯誤,僅此而已。(當然,另一個可能性是,編譯器或鏈接器有問題,但不要拿這種可能性來困擾我們。)

對于運行時錯誤來說,情況大不一樣。在某次運行期間程序沒有產生任何運行時錯誤,你就能確信另一次不同的運行期內不會產生錯誤嗎?比如:在另一次運行中,你以不同的順序做事,或者采用不同的數據,或者運行更長或更短時間,等等。你可以不停地測試自己的程序直到面色發紫,但你還是不能覆蓋所有的可能性。因而,運行時發現錯誤比在編譯鏈接期間檢查錯誤更不能讓人放心。

通常,對設計做一點小小的改動,就可以在編譯期間消除可能產生的運行時錯誤。這常常涉及到在程序中增加新的數據類型(參見條款M33)。例如,假設想寫一個類來表示時間中的日期,最初的做法可能象這樣:

class Date {
public:
 Date(int day, int month, int year);

 ...

};

準備實現這個構造函數,面臨的一個問題是對day和month值的合法性檢查。讓我們來看看,對于傳給month的值來說,怎么做可以免于對它進行合法性檢查呢?

一個明顯的辦法是采用枚舉類型而不用整數:

enum Month { Jan = 1, Feb = 2, ... , Nov = 11, Dec = 12 };

class Date {
public:
 Date(int day, Month month, int year);

 ...

};

遺憾的是,這不會換來多少好處,因為枚舉類型不需要初始化:

Month m;
Date d(22, m, 1857);      // m是不確定的

所以,Date構造函數還是得驗證month參數的值。

既想免除運行時檢查,又要保證足夠的安全性,你就得用一個類來表示month,你就得保證只有合法的month才被創建:

class Month {
public:
 static const Month Jan() { return 1; }
 static const Month Feb() { return 2; }
 ...
 static const Month Dec() { return 12; }

 int asInt() const/t   // 為了方便,使Month
 { return monthNumber; }     // 可以被轉換為int

private:
 Month(int number): monthNumber(number) {}

 const int monthNumber;
};

class Date {
public:
 Date(int day, const Month& month, int year);
 ...
};

這個設計在幾個方面的特點綜合確定了它的工作方式。首先,Month構造函數是私有的。這防止了用戶去創建新的month。可供使用的只能是Month的靜態成員函數返回的對象,再加上它們的拷貝。第二,每個Month對象為const,所以它們不能被改變(否則,很多地方會忍不住將一月轉換成六月,特別是在北半球)。最后一點,得到Month對象的唯一辦法是調用函數或拷貝現有的Month(通過隱式Month拷貝構造函數 ---- 見條款45)。這樣,就可以在任何時間任何地方使用Month對象;不必擔心無意中使用了沒有被初始化的對象。(否則就可能有問題。條款47進行了說明)

有了這些類,用戶幾乎不可能指定一個非法的month,甚至完全不可能 ---- 如果不出現下面這種可惡的情況的話:

Month *pm;/t/t // 定義未被初始化的指針

Date d(1, *pm, 1997);      // 使用未被初始化的指針!

但這種情況所涉及的是另一個問題,即通過未被初始化的指針取值,其結果是不可確定的。(參見條款3,看看我對 "不確定行為" 的感受)遺憾的是,我沒有辦法來防止或檢查這種異端行為。但是,如果假設這種情況永遠不會發生,或者如果我們不考慮這種情況下軟件的行為,Date構造函數對它的Month參數就可以免于合法性檢查。另一方面,構造函數還是必須檢查day參數的合法性 ---- 九月,四月,六月和十一月各有多少天呢?

Date的例子將運行時檢查用編譯時檢查來取代。你可能想知道什么時候可以使用鏈接時檢查。實際上,不是經常這么做。C++用鏈接器來保證所需要的函數只被定義一次(參見條款45,"需要" 一個函數會帶來什么)。它還使用鏈接器來保證靜態對象(參見條款47)只被定義一次。你可以用同樣的方法使用鏈接器。例如,條款27說明,對于一個顯式聲明的函數,如果想有意禁止對它進行定義,鏈接器檢查就很有用。

但不要過于強求。想消除所有的運行檢查是不切實際的。例如,任何允許交互式輸入的程序都要進行輸入驗證。同樣地,某個類中如果包含需要執行上下限檢查的數組,每次訪問數組時就要對數組下標進行檢查。盡管如此,將檢查從運行時轉移到編譯或鏈接時一直是值得努力的目標,只要實際可行,就要追求這一目標。這樣做的獎賞是,程序會更小,更快,更可靠。

上一篇:DataList控件也玩分頁

下一篇:返回列表

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 萌白酱福利视频在线网站 | 免费一级毛片免费播放 | 青青草免费观看完整版高清 | 91中文在线观看 | 精品国产96亚洲一区二区三区 | 免费一级毛片在线播放视频老 | 黄www片 | 中文字幕在线观看免费 | 一级黄色毛片播放 | 久久久成人免费视频 | 天天色宗合| 免费国产在线观看 | 色猫av | 久久久久久久久久91 | 国产一区二区在线观看视频 | 久久久精品福利 | 亚洲国产精久久久久久久 | wwwcom国产 | 天天操综 | 在线成人亚洲 | 综合网天天色 | 国产一级二级在线播放 | 91网在线播放 | 欧美特黄特色视频 | 天天草天天干天天射 | 久久人人爽人人爽人人片av免费 | 亚洲午夜影院在线观看 | 国产精品久久在线观看 | 中文字幕精品在线视频 | 精品一区二区亚洲 | 一区二区三高清 | 精品一区免费 | 成人小视频免费在线观看 | 91短视频版高清在线观看www | 国产精品久久久久久久久久久久久久久 | 成人三级电影网址 | 大片毛片 | 日本一道aⅴ不卡免费播放 久久久久久久高清 | 久久免费看毛片 | 国产一级爱c视频 | 免费h片网站 |