Re: [問題] 右值引用的背後原理或如何達到的

作者: littleshan (我要加入劍道社!)   2016-07-26 00:57:45
※ 引述《Clangpp (Clang++)》之銘言:
: 利用move來減少複製一份的成本
: 但是我想問背後的到底是怎麼達到的??
: 要去研究編譯器的行為
醜話先說在前頭
move 對 POD type 來說並不會變快
得益的只有掌握資源的 class type
比如說 string、vector 等等
這類 class 在建構時會配置記憶體或其它種類的資源
因此在複製時必須使用 deep copy 以確保資源不會重覆釋放
以 string 來說,假設 a, b 都是 string class,
然後我們寫 a = b 時
設計 string class 的人知道我們不能放任 C++ 直接複製指向字元陣列的指標
這樣當 a 與 b 都解構時會造成 double delete
因此他會在 copy assignment 中另外配置記憶體並且把資料完整複製
執行完 a = b 之後,a 和 b 都是完整而且內容相同的 string 物件
但是當你寫 a = move(b) 時
意思是「我不會再使用 b 了,把 b 擁有的資源原封不動轉移到 a」
執行結束後 a 擁有 b 的資源,但是 b 的內容則是 unspecified
你唯一能做的事是使用 b = XXX 來讓他擁有別的內容
因此在實作 move assignment 時,只需要直接把 b 的陣列指標以及長度丟給 a
然後把 b 設定成沒有內容的狀態即可
做這些事不需要另外配置記憶體也不需要複製內容,自然比 copy assignment 還要快
: 問題2
: 為什麼我目前看到好像沒有其他語言做這件事情??
: 像這相關的東西要如何了解??
: 謝謝
具備 move semantics 的語言並不算少見
rust 的自訂型別包括 enum 與 struct
預設情況下「只有」move assignment
而且會在 compile time 把錯誤使用物件的情況抓出來
比如說你寫
let a = String::from("abc"); // a 是字串 "abc"
let b = a; // 相當於 b = std::move(a)
let c = a; // 相當於 c = std::move(a)
這時候 compiler 會報錯,然後跟你說在 b = a 之後 a 已經失去資源,
因此沒辦法再 move 到 c 上面
當然你可以為自訂型別添加 copy assignment
那麼用起來就會比較接近 int float 之類的內建型別
另外 d language 的 struct 並沒有所謂的 copy constructor
取而代之的是個稱為 postblit function 的東西
當你在 d 裡面複製一個 struct object 時
compiler 會先把 struct 所有欄位複製一份到新的 object 上
接著在新的 object 上呼叫 postblit function
它的任務是確保資源處在正確的 state 上
因此,對 POD 來說,postblit 就是什麼事都不用做,
而對其它擁有資源的 struct,postblit 就是依照原本的內容製作複本
或是增加 reference count
最後,compiler 的最佳化會消除沒有必要的 postblit call
比如說若 compiler 發現 postblit 後緊接著另一個同樣的物件會解構
那麼這個 postblit 與解構式會同時被消除掉
這就相當於節省了一次複製
D lang 的 postblit 比 C++ 的 rvalue 要簡化許多
而代價就是 struct 內的欄位不能夠包含指向同物件內其它欄位的指標
否則在上面消除 postblit 與解構式之後,執行結果可能會錯誤
主流的 OOP 語言如 C# 與 Java,物件通常都是 reference type
因為複製 reference 相當快速,因此自然是不需要 move semantics
而 C# 雖然有 struct,但是它沒有 destructor,只能當 POD 使用
因此也不需要 move semantics (對POD來說沒差)
最後,functional language 通常變數都是 immutable type
immutable type 同樣具備複製非常快的特性 (也是只要複製 reference 呵呵)
所以它們通常也不需要 move semantics
作者: Caesar08 (Caesar)   2016-07-26 01:02:00
作者: james732 (好人超)   2016-07-26 01:06:00
作者: LPH66 (-6.2598534e+18f)   2016-07-26 01:12:00
作者: Frozenmouse (*冰之鼠*)   2016-07-26 07:36:00
作者: Clangpp (Clang++)   2016-07-26 07:59:00
推 真的太感謝了!!!
作者: Ebergies (火神)   2016-07-26 09:09:00
推 呵呵
作者: shadow0326 (非議)   2016-07-26 10:30:00
今天又學到了新東西
作者: lc85301 (pomelocandy)   2016-07-26 20:39:00
推一個
作者: easyman (oops)   2016-07-26 21:35:00
太強了
作者: ko27tye (好滋好滋)   2016-07-27 01:27:00
作者: BlazarArc (Midnight Sun)   2016-07-27 21:02:00
作者: Sidney0503 (Sidney0503)   2016-07-30 17:55:00

Links booklink

Contact Us: admin [ a t ] ucptt.com