精華區beta C_and_CPP 關於我們 聯絡資訊
小弟我想請問一下,右值引用是一個可以加快程式效能的一種好方法 個人知道怎麼使用 ex C++98 template<class T> void swap(T& a, T& b) { T tmp(a); a = b; b = tmp; } ex C++11的swap template<class T> void swap(T& a, T& b) { T tmp(std::move(a)); a = std::move(b); b = std::move(tmp); } 利用move來減少複製一份的成本 但是我想問背後的到底是怎麼達到的?? 要去研究編譯器的行為 問題2 為什麼我目前看到好像沒有其他語言做這件事情?? 像這相關的東西要如何了解?? 謝謝 -- C++是雙截棍,揮舞起來很強悍。 很吸引人,但需要你多年的磨練來掌握。 很多人希望改用別的武器。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.166.216.121 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1469456171.A.23F.html
CoNsTaR: 印象中 agda 好像也有 rvalue-reference 只是目的不是改 07/25 22:35
CoNsTaR: 善程式效能 07/25 22:35
CoNsTaR: 好像是增強程式安全性的樣子 忘記是不是 agda 了啦…… 07/25 22:35
CoNsTaR: 總之 reference 不只 C++ 有 07/25 22:35
> -------------------------------------------------------------------------- < 作者: littleshan (我正在想要換什麼) 看板: C_and_CPP 標題: Re: [問題] 右值引用的背後原理或如何達到的 時間: Tue Jul 26 00:57:45 2016 ※ 引述《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