C++臨時變數的生命週期(const 引用後延長臨時變數週期)
阿新 • • 發佈:2019-02-13
C++ 中的臨時變數指的是那些由編譯器根據需要在棧上產生的,沒有名字的變數。主要的用途主要有兩類:
1) 函式的返回值, 如:
1 string proc() 2 { 3 return string("abc"); 4 } 5 6 int main() 7 { 8 proc(); 9 return 0; 10 }
其中第 8 行會產生一個臨時變數。但並不是所有返回值都會建立臨時變數,只有當沒有將返回值賦值給其它變數時,臨時變數才會建立。這種臨時變數的生命週期很短,當表示式完成後,它就會被銷燬了。例如上面的程式碼,第 8 行產生的臨時變數,到第 9 行的時候就已經銷燬了。
2) 型別轉換時的中間變數。
1 int a = 3; 2 3 float k = 2.0; 4 float f = k + a;
第4行,k+a 由於是 float + int , int 會被轉換成 float 再與 k 相加,這個時候就會生產一個臨時變數。上面的例子是 build-in type,但對於自定義的類也是同樣適用的。
一般來說,C++ 中的臨時變數在表示式結束之後 (full expression) 就被會銷燬,比如前面舉的兩個例子,但也有例外的時候,如果這個臨時變數被用來初始化一個引用的話,那這個臨時變數的生命週期就會被延長,直到引用被銷燬,從而不會因此產生懸空(dangling)的引用。
1 string Proc() 2 { 3 return string("abc"); 4 } 5 6 int main() 7 { 8 const string& ref = Proc(); 9 cout << ref << endl; 10 return 0; 11 }
如上,第 8 行產生的臨時變數因為有 ref 指向,它的生命週期會延長至直到 main() 返回。這個特性有時很有用,比如,你可以用一個基類的引用指向一個子類的臨時變數,然後通過這個引用來實現多型,但又不用處理子類的銷燬。
1 Class Base() 2 { 3 public: 4 5 virtual Bar() { cout << "base bar()" << endl; } 6 }; 7 8 Class DerOne: public Base 9 { 10 public: 11 12 virtual Bar() { cout << "DerOne Bar()" << endl; } 13 }; 14 15 class DerTwo: public Base 16 { 17 public: 18 19 virtual Bar() { cout << "DerTwo Bar()" << endl; } 20 }; 21 22 23 Base GetBase() 24 { 25 return Base(); 26 } 27 28 DerOne GetDerOne() 29 { 30 return DerOne(); 31 } 32 33 DerTwo GetDerTwo() 34 { 35 return DerTwo(); 36 } 37 38 39 int main() 40 { 41 const Base& ref1 = GetBase(); 42 const Base& ref2 = GetDerOne(); 43 const Base& ref3 = GetDerTwo(); 44 45 ref1.Bar(); 46 ref2.Bar(); 47 ref3.Bar(); 48 49 return 0; 50 }
該小技巧在 Loki::ScopeGuard 的實現中被用到了,使得在一個域內使用多型時,可以避免使用指標,這個寫法是這樣的巧妙以致被 Andrei 稱為:"The Most Important const"。不過需要注意的是,臨時變數只能通過 const 引用來指向,因此是不可修改的。