国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

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

C++箴言:只要有可能就推遲變量定義

2019-11-17 05:34:31
字體:
來源:轉載
供稿:網友

  在極大程度上,為你的類(包括類模板)和函數(包括函數模板)提供正確的定義是戰斗的要害性部分。一旦你得到正確的結果,相應的實現很大程度上就是直截了當的。但是仍然有一些注重事項需要當心。過早地定義變量會對性能產生拖累。過度使用強制轉換會導致緩慢的,難以維護的,被微妙的 bug 困擾的代碼。返回一個類內部構件的句柄會破壞封裝并將空懸句柄留給客戶。疏忽了對異常產生的影響的考慮會導致資源的泄漏和數據結構的破壞。過分內聯化(inlining)會導致代碼膨脹。過度的耦合會導致令人無法接受的漫長的建構時間。 這一切問題都可以避免。

  只要有可能就推遲變量定義

  只要你定義了一個帶有構造函數和析構函數的類型的變量,當控制流程到達變量定義的時候會使你擔負構造成本,而當變量離開作用域的時候會使你擔負析構成本。假如有無用變量造成這一成本,你就要盡你所能去避免它。

  你可能認為你從來不會定義無用的變量,但是也許你應該再想一想。考慮下面這個函數,只要 passWord 的長度滿足要求,它就返回一個 password 的加密版本。假如 password 太短,函數就會拋出一個定義在標準 C++ 庫中的 logic_error 類型的異常(參見 Item 54):

// this function defines the variable "encrypted" too soon
std::string encryptPassword(const std::string& password)
{
  using namespace std;

  string encrypted;

  if (password.length() < MinimumPasswordLength) {
   throw logic_error("Password is too short");
  }
  ... // do whatever is necessary to place an
  // encrypted version of password in encrypted
  return encrypted;
}


  對象 encrypted 在這個函數中并不是完全無用,但是假如拋出了一個異常,它就是無用的。換句話說,即使 encryptPassword 拋出一個異常,你也要為構造和析構 encrypted 付出代價。因此得出以下結論:你最好將 encrypted 的定義推遲到你確信你真的需要它的時候:

// this function postpones encrypted’s definition until it’s truly necessary
std::string encryptPassword(const std::string& password)
{
  using namespace std;

  if (password.length() < MinimumPasswordLength) {
   throw logic_error("Password is too short");
  }

  string encrypted;
 
  ... // do whatever is necessary to place an
  // encrypted version of password in encrypted
  return encrypted;
}

  這一代碼仍然沒有達到它本可以達到的那樣緊湊,因為定義 encrypted 的時候沒有任何初始化參數。這就意味著很多情況下將使用它的缺省構造函數,對于一個對象你首先應該做的就是給它一些值,這經常可以通過賦值來完成我已經解釋了為什么缺省構造(default-constrUCting)一個對象然后賦值給它比用你真正需要它持有的值初始化它更低效。那個分析也適用于此。例如,假設 encryptPassword 的核心部分是在這個函數中完成的:

void encrypt(std::string& s); // encrypts s in place
  那么,encryptPassword 就可以這樣實現,即使它還不是最好的方法:

// this function postpones encrypted’s definition until
// it’s necessary, but it’s still needlessly inefficient
std::string encryptPassword(const std::string& password)
{
  ... // check length as above

  std::string encrypted; // default-construct encrypted
  encrypted = password; // assign to encrypted

  encrypt(encrypted);
  return encrypted;
}

  一個更可取得方法是用 password 初始化 encrypted,從而跳過毫無意義并可能很昂貴的缺省構造:

// finally, the best way to define and initialize encrypted
std::string encryptPassword(const std::string& password)
{
  ... // check length

  std::string encrypted(password); // define and initialize
  // via copy constructor

  encrypt(encrypted);
  return encrypted;
}

  這個建議就是本 Item 的標題中的“只要有可能(as long as possible)”的真正含義。你不僅應該推遲一個變量的定義直到你不得不用它之前的最后一刻,而且應該試圖推遲它的定義直到你得到了它的初始化參數。通過這樣的做法,你可以避免構造和析構無用對象,而且還可以避免不必要的缺省構造。更進一步,通過在它們的含義已經非常明確的上下文中初始化它們,有助于對變量的作用文檔化。

  “但是對于循環會如何?”你可能會有這樣的疑問。假如一個變量僅僅在一個循環內使用,是循環外面定義它并在每次循環迭代時賦值給它更好一些,還是在循環內部定義這個變量更好一些呢?也就是說,下面這兩個大致的結構中哪個更好一些?

// ApPRoach A: define outside loop // Approach B: define inside loop

Widget w;
for (int i = 0; i < n; ++i){ for (int i = 0; i < n; ++i) {
w = some value dependent on i; Widget w(some value dependent on i);
... ...
} }

  這里我將一個類型 string 的對象換成了一個類型 Widget 的對象,以避免對這個對象的構造、析構或賦值操作的成本的任何已有的預見。

  對于 Widget 的操作而言,就是下面這兩個方法的成本:

  方法 A:1 個構造函數 + 1 個析構函數 + n 個賦值。

  方法 B:n 個構造函數 + n 個析構函數。

  對于那些賦值的成本低于一個構造函數/析構函數對的成本的類,方法 A 通常更高效。非凡是在 n 變得很大的情況下。否則,方法 B 可能更好一些。此外,方法 A 與方法 B 相比,使得名字 w 在一個較大的區域(包含循環的那個區域)內均可見,這可能會破壞程序的易理解性和可維護性。因此得出以下結論:除非你確信以下兩點:(1)賦值比構造函數/析構函數對成本更低,而且(2)你正在涉及你的代碼中的性能敏感的部分,否則,你應該默認使用方法 B。

  Things to Remember

  ·只要有可能就推遲變量定義。這樣可以增加程序的清楚度并提高程序的性能。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 奈曼旗| 红安县| 深圳市| 霍州市| 读书| 无为县| 马龙县| 广南县| 黄平县| 万山特区| 犍为县| 澄江县| 雷州市| 成都市| 布拖县| 宜良县| 驻马店市| 五华县| 渑池县| 彭泽县| 花莲市| 台前县| 巧家县| 安宁市| 漯河市| 阳新县| 中山市| 香格里拉县| 鹿泉市| 芮城县| 翼城县| 景泰县| 牡丹江市| 贵溪市| 繁昌县| 迭部县| 偃师市| 阜康市| 东阳市| 昌都县| 天镇县|