More Effective C++ 條款19 (轉)
條款19:理解臨時的來源:namespace prefix = o ns = "urn:schemas--com::office" />
當員之間進行交談時,他們經常把僅僅需要一小段時間的變數稱為臨時變數。例如在下面這段s()例程裡:
template
void swap(T& 1, T& object2)
{
T temp = object1;
object1 = object2;
object2 = temp;
}
通常把temp叫做臨時變數。不過就C++而言,temp跟本不是臨時變數,它只是一個的區域性物件。
在C++中真正的臨時物件是看不見的,它們不出現在你的中。建立一個沒有命名的非堆(non-heap)物件會產生臨時物件。這種未命名的物件通常在兩種條件下產生:為了使函式成功而進行隱式型別轉換和函式返回物件時。理解如何和為什麼建立這些臨時物件是很重要的,因為構造和釋放它們的開銷對於程式的來說有著不可忽視的影響。
首先考慮為使函式成功呼叫而建立臨時物件這種情況。當傳送給函式的物件型別與引數型別不匹配時會產生這種情況。例如一個函式,它用來計算一個字元在字串中出現的次數:
// 返回ch在str中出現的次數
size_t countChar(const string& str, char ch);
char buffer[MAX_STRING_LEN];
char c;
// 讀入到一個字元和字串中,用setw
// 避免快取,當讀取一個字串時
cin >> c >> setw(MAX_STRING_LEN) >> buffer;
cout << "There are " << countChar(buffer, c)
<< " occurrences of the character " << c
<< " in " << buffer << endl;
看一下countChar的呼叫。第一個被傳送的引數是字元陣列,但是對應函式的正被繫結的引數的型別是const string&。僅當消除型別不匹配後,才能成功進行這個呼叫,你的很樂意替你消除它,方法是建立一個string型別的臨時物件。透過以buffer做為引數呼叫string的建構函式來初始化這個臨時物件。countChar的引數str被繫結在這個臨時的string物件上。當countChar返回時,臨時物件自動釋放。
這樣的型別轉換很方便(儘管很危險-參見條款5),但是從的觀點來看,臨時string物件的構造和釋放是不必要的開銷。通常有兩個方法可以消除它。一種是重新設計你的程式碼,不讓發生這種型別轉換。這種方法在條款5中被研究和分析。另一種方法是透過修改而不再需要型別轉換,條款21講述瞭如何去做。
僅當透過傳值(by value)方式傳遞物件或傳遞常量引用(reference-to-const
)引數時,才會發生
這些型別轉換。當傳遞一個非常量引用(reference-to-non-const
)
引數物件,就不會發生。考慮一下這個函式:
void uppercasify(string& str); // 把str中所有的字元
// 改變成大寫
在字元計數的例子裡,能夠成功傳遞char陣列到countChar中,但是在這裡試圖用char陣列呼叫upeercasify函式,則不會成功:
char subtleBookPlug[] = "Effective C++";
uppercasify(subtleBookPlug); // 錯誤!
沒有為使呼叫成功而建立臨時物件,為什麼呢?
假設建立一個臨時物件,那麼臨時物件將被傳遞到upeercasify中,其會修改這個臨時物件,把它的字元改成大寫。但是對subtleBookPlug
函式呼叫的真正引數沒有任何影響;僅僅改變了臨時從subtleBookPlug生成的string物件。無疑這不是程式設計師所希望的。程式設計師傳遞subtleBookPlug引數到uppercasify函式中,期望修改subtleBookPlug的值。當程式設計師期望修改非臨時物件時,對非常量引用(
references-to-non-const
)進行的隱式型別轉換卻修改臨時物件。這就是為什麼C++語言禁止為非常量引用(
reference-to-non-const
)產生臨時物件。這樣非常量引用(
reference-to-non-const
)引數就不會遇到這種問題。
建立臨時物件的第二種環境是函式返回物件時。例如operator+必須返回一個物件,以表示它的兩個運算元的和(參見Effective C++ 條款23)。例如給定一個型別Number,這種型別的operator+被這樣宣告:
const Number operator+(const Number& lhs,
const Number& rhs);
這個函式的返回值是臨時的,因為它沒有被命名;它只是函式的返回值。你必須為每次呼叫operator+構造和釋放這個物件而付出代價。(有關為什麼返回值是const的詳細解釋,參見Effective C++條款21)
通常你不想付出這樣的開銷。對於這種函式,你可以切換到operator=,而避免開銷。條款22告訴我們進行這種轉換的方法。不過對於大多數返回物件的函式來說,無法切換到不同的函式,從而沒有辦法避免構造和釋放返回值。至少在概念上沒有辦法避免它。然而概念和現實之間又一個黑暗地帶,叫做,有時你能以某種方法編寫返回物件的函式,以允許你的編譯器最佳化臨時物件。這些最佳化中,最常見和最有效的是返回值最佳化,這是條款20的內容。
綜上所述,臨時物件是有開銷的,所以你應該儘可能地去除它們,然而更重要的是訓練自己尋找可能建立臨時物件的地方。在任何時候只要見到常量引用(reference-to-const
)引數,就存在建立臨時物件而繫結在引數上的可能性。在任何時候只要見到函式返回物件,就會有一個臨時物件被建立(以後被釋放)。學會尋找這些物件構造,你就能顯著地增強透過編譯器表面動作而看到其背後開銷的能力。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1007384/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Effective C++ 條款08_不止於此C++
- Effective Modern C++ 系列之 條款2: autoC++
- Effective c++條款11:在operator=中處理“自我賦值”C++賦值
- [讀書筆記][effective C++]條款30-inline的原理筆記C++inline
- 文獻學習——Making Deduction More Effective in SAT Solvers
- 學懂現代C++——《Effective Modern C++》之轉向現代C++C++
- effective C++ : CHAPTER 8C++APT
- 【Effective Modern C++】索引C++索引
- Effective C++筆記C++筆記
- 《Effective DevOps》閱讀筆記 19dev筆記
- effective C++筆記1C++筆記
- 《Effective C++》讀書筆記C++筆記
- Effective C++ 筆記(3)資源管理C++筆記
- Effective C++ 4.設計與宣告C++
- 條款01: 視C++為一個語言聯邦C++
- 《Effective C++》閱讀總結(三):資源管理C++
- 《Effective C++》第三版-1. 讓自己習慣C++(Accustoming Yourself to C++)C++
- 學懂現代C++——《Effective Modern C++》之型別推導和autoC++型別
- 條款05: 瞭解c++默默編寫並呼叫哪些函式C++函式
- 《Effective C++》第三版-5. 實現(Implementations)C++
- 讀完Java名著《Effective Java》: 我整理了這50條技巧Java
- 《Effective C++》閱讀總結(四): 設計、宣告與實現C++
- 《Effective C++》第三版-3. 資源管理(Resource Management)C++
- c++切面條題目C++
- 常用的 19 條 MySQL 最佳化MySql
- 《Effective C++》第三版-4. 設計與宣告(Design and Declarations)C++
- 《Effective Python 第二版》第二條 遵循PEP8風格指南Python
- C++整理19_異常處理C++
- 《Effective C++》閱讀總結(二):類的構造、析構和賦值C++賦值
- 《看雪服務條款》
- 學習進度條2024-03-19
- 【C++】C++之型別轉換C++型別
- C++中的條件變數C++變數
- MORE_DETAIL_TECHAI
- TypeScript 之 More on FunctionsTypeScriptFunction
- More web function requests go online concurrently, and web service deployment is faster and more economical!WebFunctionGoAST
- effective java 觀後感Java
- 提高軟體測試能力的19條建議
- [20210420]19c奇怪的過濾條件.txt