c++臨時變數的作用域
上上週週末翻《effective c++》,條款18看到一段程式碼:
class Date {
public:
Date(const Month& m, const Day& d, const Year& y);
...
};
class Month {
public:
static Month Jan() { return Month(1); }
};
Date d(Month::Jan(), Day(30), Year(1995));
看到這裡的時候,猛然感覺有問題。
在函式d(Month::Jan(), Day(30), Year(1995));中(也就是Data的建構函式),第一個變數為const Month& m,是一個引用,而函式Jan()返回了一個臨時變數(返回值儲存在棧中,之後通過拷貝構造臨時變數)。也就是說,將一個引用指向了一個臨時變數,而且這個臨時變數的作用域非常不明確。初看上去,在Data()的第一個引數賦值完成後,臨時變數就失效了。
當時在網上找了好久,期望看到其他人對這段程式碼的異議,可惜沒有發現。
週二的時候,問了一下師兄。
師兄說這樣是有問題的,估計編譯都會出現警告,但是如果Date的建構函式中做了特殊的實現(比如變數拷貝等等),那麼這樣寫就是正確的。我想了想,確實有道理,師兄還提出了一個觀點:c++裡似乎會延長這樣的臨時變數的作用域。他建議我去看一下這段程式碼的彙編實現,就能徹底搞清楚了。
可是我不以為然,想當然的篤定這樣的程式碼肯定會編譯失敗。
而且覺得,這樣的可能存在爭議的程式碼,本來就不應該寫出來,如果是我來實現,會在static Month Jan()中增加一個static Month(1)成員,效率高,邏輯清晰。
以至於後來也確實沒有去反彙編這段程式碼,甚至都沒有去驗證是否存在編譯警告問題......
這件事本來就這樣過去了,可是今天繼續翻《effective c++》的時候,又看到了一段程式碼:
class Rational {
public:
Rational(int numberator = 0,
int denominator = 1); //允許隱式轉換
...
};
const Rational operator* (const Rational& lhs,
const Rational& rhs)
{...}
Rational oneFourth(1, 4);
Rational result;
result = 2 * oneFourth;
明顯的,這裡一樣使用了臨時變數,書上明確寫了一句話: “萬歲,通過編譯了”。
看來這樣做,編譯是可以成功的,而且好像是一種再普通不過的用法。
於是一邊哀嘆自己的淺薄,一邊去查資料搞定這個問題。
終於在c++標準裡找到這樣的解釋:
C++標準對臨時物件的生存期(life time)的規定,可見標準12.2節第3-5條。第3條討論了臨時物件的析構時間:
3 .... Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception.(這其中涉及到的full-expression的定義,參見1.9節,一般指對一個變數的初始化)。
但在第4、5條中,分別討論了兩個例外情形,
1 將臨時物件作為初始化因子,例如string s = string("hello world");
2 將一個常量引用變數繫結到這個臨時物件上。
在這兩種情況中可以通過一個名字來存取這個物件,此物件的生存期就將延長到變數名的作用域結束。除此之外,都按照第3條處理。
這樣解釋之後,一切順理成章。
(原文時間2013-10-1)
相關文章
- C++臨時變數的生命週期C++變數
- 酒店房間和 C++ 區域性變數的作用域C++變數
- 變數作用域變數
- lisp 變數的作用域Lisp變數
- JS變數作用域JS變數
- SCSS 變數作用域CSS變數
- golang變數作用域Golang變數
- java中變數的作用域Java變數
- JavaScript 變數的作用域鏈JavaScript變數
- python變數與變數作用域Python變數
- PL/SQL變數作用域SQL變數
- LoadRunner變數作用域變數
- C# 變數作用域C#變數
- 現代 JavaScript 的變數作用域JavaScript變數
- Go語言中的變數作用域Go變數
- Shell變數的作用域問題變數
- 變數的作用域--js閉包變數JS
- 理解 Javascript 中變數的作用域JavaScript變數
- javascript中的作用域(全域性變數和區域性變數)JavaScript變數
- C++ 煉氣期之變數的生命週期和作用域C++變數
- TempDB 中表變數和區域性臨時表的對比變數
- 變數物件與作用域鏈變數物件
- JavaScript中變數和作用域JavaScript變數
- JavaScript之變數及作用域JavaScript變數
- Go 語言變數作用域Go變數
- JavaScript變數作用域之殤JavaScript變數
- Go 中的動態作用域變數Go變數
- 注意for迴圈中變數的作用域變數
- 函式(三)作用域之變數作用域、函式巢狀中區域性函式作用域、預設值引數作用域函式變數巢狀
- 變數、作用域與記憶體變數記憶體
- ES6(二: 變數作用域)變數
- js中變數作用域問題JS變數
- Java 8 之 lambda 變數作用域Java變數
- Day08-常量、變數、作用域變數
- PHP 變數的四大作用域PHP變數
- CSS變數的作用域和預設值CSS變數
- 變數的作用域最小化原則變數
- 不使用臨時變數交換兩個變數的值變數