// 此函數太早定義了變量"encrypted" string encryptPassword(const string& password) {string encrypted;//默認構造函數初始化if (password.length() < MINIMUM_PASSWORD_LENGTH) {throw logic_error("Password is too short");}進行必要的操作,將口令的加密版本 放進encrypted之中;return encrypted; }
對象encrypted在函數中并非完全沒用,但如果有異常拋出時,就是無用的。但是,即使encryptPassword拋出異常(見條款M15),程序也要承擔encrypted構造和析構的開銷。所以,最好將encrypted推遲到確實需要它時才定義:
// 這個函數推遲了encrypted的定義, // 直到真正需要時才定義 string encryptPassword(const string& password) {if (password.length() < MINIMUM_PASSWORD_LENGTH) {throw logic_error("Password is too short");}string encrypted;進行必要的操作,將口令的加密版本 放進encrypted之中;return encrypted; }
這段代碼還不是那么嚴謹,因為encrypted定義時沒有帶任何初始化參數。這將導致它的缺省構造函數被調用。大多數情況下,對一個對象首先做的一件事是給它一個什么值,這通常用賦值來實現。條款12說明了為什么"缺省構造一個對象然后對它賦值"(調用缺省構造函數初始化和拷貝賦值運算符賦值)比"用真正想要的值來初始化這個對象"(顯式調用構造函數初始化)效率要低得多。這一論斷在此一樣適用。例如,假設encryptPassword中最難處理的部分在這個函數中進行:
void encrypt(string& s);????? // s在此加密
于是encryptPassword可以象這樣實現(當然,它不是最好的實現方式):
// 這個函數推遲了encrypted的定義, // 直到需要時才定義,但還是很低效 string encryptPassword(const string& password) {... // 同上,檢查長度string encrypted; // 缺省構造encryptedencrypted = password; // 給encrypted賦值 encrypt(encrypted);return encrypted; }
更好的方法是用password來初始化encrypted,從而繞過了對缺省構造函數不必要的調用:
// 定義和初始化encrypted的最好方式 string encryptPassword(const string& password) {... // 檢查長度string encrypted(password); // 通過拷貝構造函數定義并初始化 encrypt(encrypted);return encrypted; }
?
你不僅要將變量的定義推遲到必須使用它的時候,還要盡量推遲到可以為它提供一個初始化參數為止。這樣做,不僅可以避免對不必要的對象進行構造和析構,還可以避免無意義的對缺省構造函數的調用。而且,在對變量進行初始化的場合下,變量本身的用途不言自明,所以在這里定義變量有益于表明變量的含義。
?