看板 C_and_CPP 關於我們 聯絡資訊
開發平台(Platform): (Ex: Win10, Linux, ...) win10 1803 WSL@Debian 編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出) g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516 c++11 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...) <iostream> 問題(Question): 有兩個相似的case,煩請參照外部連結閱讀;編譯以及執行的選項如下 $ g++ -c my_PTT_post.cc --std=c++11 -O0 -Wall -fno-elide-constructors $ g++ -o test my_PTT_post.o $ ./test 想要使用這些編譯選項以免除NRVO/RVO,方便觀察ctor呼叫行為 兩個case的差異僅在於 // case1,pass by value myClass g (myClass other); // case2,pass by rvalue reference myClass g (myClass&& other); 以下是case1的結果以及個人的理解 (myClass g( myClass other ); ) ctor // ctor without parameter inside function f mv ctor // returned object of f steal the rvalue created by ctor mv ctor // obj1 steal RHS of "=" sign; RHS is a rvalue expression ctor // ctor without parameter inside function f inside function g mv ctor // returned object of f steal the rvalue created by ctor mv ctor // parameter of g steal what returned by f, which is rvalue inside g // now inside function g mv ctor // returned object of g steal the glvalue in g, which is at the end of its lifespan mv ctor // obj2 steal RHS of "=" sign, which is a rvalue expression 以下是case2的結果以及個人的理解 (myClass g( myClass&& other ); ) ctor // ctor without parameter inside function f mv ctor // returned object of f steal the rvalue created by ctor mv ctor // obj1 steal RHS of "=" sign; RHS is a rvalue expression ctor // ctor without parameter inside function f inside function g mv ctor // returned object of f steal the rvalue created by ctor inside g // g takes rvalue reference, so we step into g directly cp ctor // returned object of g is a copy of the rvalue reference in g mv ctor // obj2 steal RHS of "=" sign; RHS being a rvalue expression 不懂的地方有2: 1. operator =以及obj1/obj2原本自己的ctor怎麼都沒有被呼叫呢? 還是case1、case2當中(應該要)呼叫ctor without parameter以及operator =的寫法 myClass obj1 = f(); myClass obj2 = g(f()); 實際上等同沒有用到ctor w/o parameter、operator =,僅用到mv/cp ctor myClass obj1(f()); myClass obj2(g(f())); 的這個寫法呢? 2. case2當中,最後有一個copy ctor被呼叫了 這個copy ctor應該是為了把g吃進來的rvalue reference return回外面 但是為甚麼需要用到copy ctor呢? 除非使用者故意用了std::move()把expression轉成rvalue丟進g 不然這個reference所代表的東西應該會是馬上就要過期的rvalue 一般情況下如同case1呼叫mv ctor可以省一些資源吧? 餵入的資料(Input): nope 預期的正確結果(Expected Output): 如問題描述 錯誤結果(Wrong Output): 應該是我有哪裡搞錯了QQ 程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔) case1: https://godbolt.org/g/hBX1yw case2: https://godbolt.org/g/nXqyYc 補充說明(Supplement): 煩請各位指點 m(_ _)m -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.233.88.219 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1529748654.A.1FC.html
bluesoul: 1你的理解是對的 06/23 18:50
KanzakiHAria: 縮寫看得很不舒服 Constructor就打完整 06/23 20:25
KanzakiHAria: 一個物件實體化第一次的=不會使用operator= 06/23 20:26
KanzakiHAria: 所以第一次=會呼叫constructor 06/23 20:26
KanzakiHAria: move可能慢的原因為複製成本太低 06/23 20:27
KanzakiHAria: std::move是一個function 所以還是會有離開回來 06/23 20:28
KanzakiHAria: 例如int 型態還特地調用move就會造成過多的搬移成本 06/23 20:28
KanzakiHAria: move最值得使用的情境為:當一個需要deep copy的物 06/23 20:29
KanzakiHAria: 件要用來初始化別人,這時候move就不需要copy 06/23 20:30
KanzakiHAria: 但是如果這個東西之後還要繼續用就無法使用move 06/23 20:30
KanzakiHAria: 那只好回到使用copy 06/23 20:30
KanzakiHAria: 簡單說可以想像類似搬進去function的scope 06/23 20:32
KanzakiHAria: 離開function 的時候這個東西會destruct 06/23 20:32
legendmtg: ctor是很慣用的縮寫吧 06/23 20:37
chchwy: 並沒有什麼實體化第一次不呼叫operator=的規則 06/23 20:41
chchwy: 那是因為編譯器開了RVO 你把RVO關掉就可以看見正確行為 06/23 20:42
chchwy: 然後ctor/dtor根本就超常見 06/23 20:42
我以為已經關掉RVO了耶 參照 https://goo.gl/3D5p3x 有在編譯選項加 -fno-elide-constructors 根據內文貼的code連結,比較了一下問題一提到的兩種寫法產生的組語 (編譯選項同內文所提) 發現main裡面的組語一模一樣 因此這部份結果應該如藍魂、神崎亞莉亞所提 compiler對於兩種寫法的處理方式是一樣的 這裡( https://stackoverflow.com/a/8777310 )的回答也認為compiler是這樣處理的 不過還是不太懂問題二的部份 甚麼情況下編譯器會決定用mv ctor來把東西傳回外界 又是甚麼時候會決定優先採用cp ctor啊? ※ 編輯: a58524andy (36.233.88.219), 06/23/2018 22:06:24
Feis: 名字 06/24 01:09
BlazarArc: ctor很常見的縮寫 06/24 01:19
Feis: case 2. reference (cp), std::move (mv) 06/24 01:25
steve1012: ctor 很ok的 06/24 03:46
KanzakiHAria: 你在講什麼?constructor的return是void哪有甚麼回傳 06/24 06:20
KanzakiHAria: function return都是rvalue 建構子也是 06/24 06:27
KanzakiHAria: 我終於看懂你的問題了...... 06/24 06:45
KanzakiHAria: 因為你的g不是回傳reference type 06/24 06:45
KanzakiHAria: 當然不會動到reference的constructor阿...... 06/24 06:46
KanzakiHAria: 你的問題是連最基本的三種呼叫和回傳都沒搞懂 06/24 06:48
KanzakiHAria: call by value, call by address,call by reference 06/24 06:48
firose: 這問題 (https://bit.ly/2K5zUvu) 也有人問但沒答案 06/24 07:04
firose: 感覺他是 xvalue 應該能安全 move 才對 06/24 07:06
KanzakiHAria: 因為在function內scope是lvalue reference 06/24 07:34
KanzakiHAria: 也就是原PO的22行還要使用move才會cast回rvalue ref 06/24 07:37
KanzakiHAria: erence 06/24 07:37
firose: 問題是 case1 也是 lvalue 就可以 move 06/24 07:53
KanzakiHAria: 所以是RVO關不掉? 06/24 07:58
KanzakiHAria: RVO是c++11的standard 06/24 07:59
KanzakiHAria: 名稱是copy elision 06/24 08:00
KanzakiHAria: 我把原PO的code改了一下 http://cpp.sh/4u437 06/24 08:45
KanzakiHAria: 28行VS報錯內容 06/24 08:46
KanzakiHAria: 'return': cannot convert from 'myClass' to 'myCl 06/24 08:46
KanzakiHAria: ass &&' 06/24 08:46
KanzakiHAria: Clang報錯內容 06/24 08:47
KanzakiHAria: rvalue reference to type 'myClass' cannot bind t 06/24 08:47
KanzakiHAria: o lvalue of type 'myClass' 06/24 08:47
loveflames: return語句為非靜態物件名稱時,才以move取代copy,rv 06/24 10:40
loveflames: alue ref並不是一個物件 06/24 10:40
loveflames: 還有樓上那個錯誤訊息是因為decltype(auto)是推導出my 06/24 11:06
loveflames: Class && 06/24 11:06
loveflames: 不是你以為的myClass 06/24 11:06
loveflames: 你可以把h函數想成這樣 06/24 11:07
loveflames: decltype(auto) tmp = other; 06/24 11:08
感謝推文各位 稍微整理對於回答二的意見如下 參考firose的連結 在case2中 // myClass g (myClass&& other); 在g函式裡面 吾人不能直接把"other"這個expression當成rvalue看待 否則"other"這個expression在g呼叫其他函式的時候容易被玩壞 同時參考n3337 https://goo.gl/SXrM4E ch.5 pg.97 note.6 "an expression is an xvalue if it is [...] a cast to rvalue reference to object type," "other"這個expression在g裡面應該被當成一個xvalue使用 至於這個xvalue expression傳回時的行為則如loveflames所提 實際上"other"還是一個reference而不是一個non-static object 因此採用了cp ctor而沒有採用mv ctor 如果有錯的話煩請不吝指正@@ ※ 編輯: a58524andy (36.233.88.219), 06/24/2018 16:52:45