0. 前言
最近工作稍微告一個段落
想說沒事就來研究C++
就順便把研究的心得也記錄起來
我想這應該會是一個非常長的系列
主要除了想記錄下自己的研究心得
也讓我能在多年後回首自己成長的軌跡
至於先前的資料結構系列我應該也會慢慢來補...
1. 正文
最近在研究RValue Reference / LValue Reference / Universal Reference
在開始介紹這三者前
我想先寫一點LValue / RValue的介紹
中文分別稱為左值 / 右值
比較簡單的理解LValue就是那些能出現=左右兩邊的變數
像是你所創造的變數
例如:int i; / Class Student; / std::string s;等等
而RValue只能出現在=右側
像是那些常量 / function return的值(有例外 下面會說)
例如:123 / "76ers is the championship of 2023 NBA's Final." / 0.23等等
精確一點來講
RValue就是在程式運行中並不會對其分配特定記憶體的東西
可能僅存於暫存器中
所以簡單區分LValue, RValue的方式就是對他作取址的動作
如果這運算式可行即是LValue
講完LValue與RValue的簡單介紹
來講一個算冷知識的東西
相信有些人聽過Built-in prefix operator會比Built-in postfix operator更有效率一點
Built-in prefix operator就是大家都用過的++i / --i
Built-in postfix operator為i++ / i--
要來講這兩者為什麼有效能差異
就得從這兩個operator Prototype開始講了
下面都以increment做舉例
先來看prefix operator
class內部的宣告
T& T::operator++();
class外部的宣告
T& operator++(T& a);
再來是postfix operator
class內部的宣告
T T::operator++(int);
class外部的宣告
T operator++(T& a, int);
這兩者一對比很容易就能發現不同的地方
prefix operator回傳的是reference而postfix回傳的是物件
且postfix的參數多了一個int
第一個不同就牽扯到效能的影響
晚點實作時會一併說明
而第二個不同參數多了一個int
這麼做是為了區分要呼叫prefix operator還是postfix operator
所以通常值都為0
也因此這個int亦被稱為dummy parameter
但C++支援operator overload想不加0也可以自己overload
接下來我會分class內部與外部分別實作
class內部:
class外部:
看完這兩個的實作可以來解答一個我知道結果但不知道為什麼的現象了
前者會印出1後者則會印出2
原因就在於postfix operator會用一個臨時變數保存初始的變數值
然後才執行+1
最後回傳原本的變數
所以才會得到1
而prefix operator的行為則是對reference做+1後回傳更動後的值
因此才會得到2
解決完這個從我開始寫程式就沒仔細想過的小問題
現在可以來說為什麼prefix跟postfix會有效能上的差異了
原因就在於postfix會創造一個臨時變量
不管是用copy constructor或是要重載=的方式都免不了有複製的動作
也因此如果對於較為肥大or自訂義的變數來說會影響到效能。
也因此才會建議在for loop盡量都以prefix operator來做迭代
因為這兩者就結果來說並無差異
2. 總結
結果冷知識的篇幅反而比較多
得稍微把LValue, RValue來跟它做一些連結
順便解答一下在RValue舉例我說function return的值為RValue但有例外
例外就是 當function回傳的是reference時 它會變LValue
很神奇吧
原因就在於C++對reference設計的精妙之處了
資工系 / 電機系的一定寫過C
多半會同意pointer與function結合有多痛苦吧
(望向DSA的作業...各種parameter的*比我當兵遇到的長官還要多)
扯遠了
C++引入了reference的概念
實際上它依然是一種特殊的指標
只是沒一般指標來的靈活
詳細差異這邊就不做展開介紹 因為感覺這也是能寫一篇來討論
就留到之後來寫吧
回到上面說的當function return的是reference會是LVaule
精準一點來說
這種宣告本來就是return LValue Reference的意思
也因此我們能將這種return的LValue Reference擺在=左邊
講完上面這些
我們可以來看一小段程式碼了
如果把這一小段程式碼丟去編譯
後者一定會跳不可以對RValue取址
而前者卻沒事
至於原因結合冷知識與後面做的function return LValue reference講解應該就能得到解答了
3. 延伸
我想平常應該不太會有人使用到return LValue Reference
但Design Pattern中有個Singleton Pattern就是這樣實作得
感覺Design Pattern也是可以寫好幾篇的介紹
之後有時間會慢慢來寫得
就簡單寫一小段讓大家看看C++可以寫得多酷
原本想說要再一口氣把RValue Reference / LValue Reference / Universal Reference給講完
但篇幅已經有點長了
我下一篇再繼續接著寫吧
此篇主要為研究心得
資料多蒐集自網路後 由本人的理解所饌而得
如有疏漏錯誤 尚祈各位不吝指教 感謝><