Re: [問題] unique_ptr與move、type conversion、return statement

看板C_and_CPP作者 (Caesar)時間7年前 (2016/08/13 23:28), 7年前編輯推噓4(405)
留言9則, 5人參與, 最新討論串1/1
※ 引述《james732 (好人超)》之銘言: : 標題: [問題] unique_ptr與move : 時間: Wed Aug 10 23:25:24 2016 : : 問題(Question): : https://www.chromium.org/rvalue-references : : 在上面這個網頁裡,看到這段敘述 : : However, if the types of the variable and the return type do not match : exactly, then you will have to use std::move() in order to convert without : creating an extra temporary. : : std::unique_ptr<MyType> MakeMyType() : { : std::unique_ptr<ChildClassOfMyType> ptr; : // This call to std::move() is needed to convert from a pointer-to-the : // child class to a pointer-to-the parent. : return std::move(ptr); : } : : 我看不懂的是…為什麼這樣寫可以減少extra temporary呢? : 如果不這麼寫的話又會造成什麼問題? : (想知道這個寫法的反例?) : : -- : ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 223.137.25.206 : ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1470842731.A.732.html : → Caesar08: 因為不這麼做,不能通過compile? 08/10 23:40 : → Caesar08: 可是我在MSVC跟GCC上,又都能通過compile... 08/10 23:40 : → Caesar08: 對於要convert type的unique_ptr,unique_ptr的 08/10 23:43 : → Caesar08: constructor只接受r value。所以應該是這原因導致要move 08/10 23:43 : → Caesar08: 可能是return value都會當作r value,然後能用RVO的就用 08/10 23:45 : → Caesar08: 所以就剛好可以通過編譯了吧。以上是我的猜測,請求支援 08/10 23:46 因為都沒人支援我,所以我只好自己支援自己了 我覺得google文件說的半對半錯 對的是return statement的expression要寫成move(ptr) unique_ptr的constructor裡,跟copy or move有關的是以下兩者 unique_ptr(unique_ptr&& u) noexcept; (1) template <class U, class E>unique_ptr(unique_ptr<U, E>&& u) noexcept; (2) 所以unique_ptr只能變成rvalue來construct另一個unique_ptr 因此這邊要寫上move(ptr) 錯的是"without creating an extra temporary" 我猜google文件會這麼寫,是因為 如果是有copy constructor的class,的確要寫move來避免呼叫copy constructor 假設今天unique_ptr有copy constructor,該constructor的作用就是把指到的東西再複製一個 如果不寫move,那就會額外複製一個object,可是你的local object其實是可以直接拿來用的 這樣就會有浪費的情況 如果寫move,就會呼叫move constructor,就可以without creating an extra temporary 可是他舉的例子剛好是unique_ptr,剛好是沒有copy constructor的class 所以你才會覺得奇怪(我也覺得很奇怪) 不過如果是在C++11的標準下,的確要這樣寫 接下來要講的是C++14的事情,也就是為甚麼不寫move也不會compilation error 因為C++14的標準說,如果把local object放在return statement的expression上 那會將他視為rvalue,即使你沒有寫move(太神啦) 也就是說, 假設return type有move constructor,那就會呼叫這個move constructor (如果return type的move constructor是delete,那到時候會有compilation error) 如果沒有move constructor,才會呼叫copy constructor 對於以往的code,如果programmer沒有寫move,那仍會呼叫move constructor 如果沒有move constructor,那也只不過就是繼續呼叫copy constructor 這反而會讓那些code可以跑得更快,而且沒有任何副作用,是有益無害的 不過我覺得這樣反而會讓programmer沒辦法了解背後的return機制就是了 關於這背後的機制,想要更加深了解的話,可以參考C++ standard n4594 §12.8 32 不過那串英文要小心的讀,因為我曾一直以為那是copy elision成立的時候才能使用 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.114.233.71 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1471102081.A.34C.html

08/13 23:55, , 1F
由此看來 extra object 應該是 (2) implicit 建構的物件
08/13 23:55, 1F

08/13 23:56, , 2F
關鍵點還是在 c++14 把它先視為 rvalue @@
08/13 23:56, 2F

08/14 00:08, , 3F
說錯了 @@ 應是(1)產生物件 然後再(2)move回去
08/14 00:08, 3F

08/14 00:09, , 4F
如果加 move 就直接 2 回去
08/14 00:09, 4F
move(ptr)沒辦法用(1)construct 應該是用(2)跟implicit conversion產生temporary object 再將這個temporary object move到MakeMyType()的return value

08/14 09:48, , 5F
自己發文自己回 教你啦 開分身回文比較不孤單
08/14 09:48, 5F

08/14 15:20, , 6F
推,好像有點懂了
08/14 15:20, 6F

08/15 23:11, , 7F
move可能會破壞RVO
08/15 23:11, 7F
因為move的return value是rvalue reference,不是temporary object 所以沒辦法使用copy elision

08/16 00:05, , 8F
你說的好像是這條standard, 我不是很確定
08/16 00:05, 8F

08/16 00:05, , 9F
08/16 00:05, 9F
是。但是現在那段英文改很多 ※ 編輯: Caesar08 (140.114.233.71), 08/16/2016 00:17:26
文章代碼(AID): #1Nhpo1DC (C_and_CPP)