1. 程式人生 > >C++臨時變數的生命週期(const 引用後延長臨時變數週期)

C++臨時變數的生命週期(const 引用後延長臨時變數週期)

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 引用來指向,因此是不可修改的。