[問題] 關於c++11 ctor行為

看板C_and_CPP (C/C++)作者 (a58524andy)時間7年前 (2018/06/23 18:10), 7年前編輯推噓6(7143)
留言51則, 9人參與, 7年前最新討論串1/2 (看更多)
開發平台(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

06/23 18:50, 7年前 , 1F
1你的理解是對的
06/23 18:50, 1F

06/23 20:25, 7年前 , 2F
縮寫看得很不舒服 Constructor就打完整
06/23 20:25, 2F

06/23 20:26, 7年前 , 3F
一個物件實體化第一次的=不會使用operator=
06/23 20:26, 3F

06/23 20:26, 7年前 , 4F
所以第一次=會呼叫constructor
06/23 20:26, 4F

06/23 20:27, 7年前 , 5F
move可能慢的原因為複製成本太低
06/23 20:27, 5F

06/23 20:28, 7年前 , 6F
std::move是一個function 所以還是會有離開回來
06/23 20:28, 6F

06/23 20:28, 7年前 , 7F
例如int 型態還特地調用move就會造成過多的搬移成本
06/23 20:28, 7F

06/23 20:29, 7年前 , 8F
move最值得使用的情境為:當一個需要deep copy的物
06/23 20:29, 8F

06/23 20:30, 7年前 , 9F
件要用來初始化別人,這時候move就不需要copy
06/23 20:30, 9F

06/23 20:30, 7年前 , 10F
但是如果這個東西之後還要繼續用就無法使用move
06/23 20:30, 10F

06/23 20:30, 7年前 , 11F
那只好回到使用copy
06/23 20:30, 11F

06/23 20:32, 7年前 , 12F
簡單說可以想像類似搬進去function的scope
06/23 20:32, 12F

06/23 20:32, 7年前 , 13F
離開function 的時候這個東西會destruct
06/23 20:32, 13F

06/23 20:37, 7年前 , 14F
ctor是很慣用的縮寫吧
06/23 20:37, 14F

06/23 20:41, 7年前 , 15F
並沒有什麼實體化第一次不呼叫operator=的規則
06/23 20:41, 15F

06/23 20:42, 7年前 , 16F
那是因為編譯器開了RVO 你把RVO關掉就可以看見正確行為
06/23 20:42, 16F

06/23 20:42, 7年前 , 17F
然後ctor/dtor根本就超常見
06/23 20:42, 17F
我以為已經關掉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

06/24 01:09, 7年前 , 18F
名字
06/24 01:09, 18F

06/24 01:19, 7年前 , 19F
ctor很常見的縮寫
06/24 01:19, 19F

06/24 01:25, 7年前 , 20F
case 2. reference (cp), std::move (mv)
06/24 01:25, 20F

06/24 03:46, 7年前 , 21F
ctor 很ok的
06/24 03:46, 21F

06/24 06:20, 7年前 , 22F
你在講什麼?constructor的return是void哪有甚麼回傳
06/24 06:20, 22F

06/24 06:27, 7年前 , 23F
function return都是rvalue 建構子也是
06/24 06:27, 23F

06/24 06:45, 7年前 , 24F
我終於看懂你的問題了......
06/24 06:45, 24F

06/24 06:45, 7年前 , 25F
因為你的g不是回傳reference type
06/24 06:45, 25F

06/24 06:46, 7年前 , 26F
當然不會動到reference的constructor阿......
06/24 06:46, 26F

06/24 06:48, 7年前 , 27F
你的問題是連最基本的三種呼叫和回傳都沒搞懂
06/24 06:48, 27F

06/24 06:48, 7年前 , 28F
call by value, call by address,call by reference
06/24 06:48, 28F

06/24 07:04, 7年前 , 29F
這問題 (https://bit.ly/2K5zUvu) 也有人問但沒答案
06/24 07:04, 29F

06/24 07:06, 7年前 , 30F
感覺他是 xvalue 應該能安全 move 才對
06/24 07:06, 30F

06/24 07:34, 7年前 , 31F
因為在function內scope是lvalue reference
06/24 07:34, 31F

06/24 07:37, 7年前 , 32F
也就是原PO的22行還要使用move才會cast回rvalue ref
06/24 07:37, 32F

06/24 07:37, 7年前 , 33F
erence
06/24 07:37, 33F

06/24 07:53, 7年前 , 34F
問題是 case1 也是 lvalue 就可以 move
06/24 07:53, 34F

06/24 07:58, 7年前 , 35F
所以是RVO關不掉?
06/24 07:58, 35F

06/24 07:59, 7年前 , 36F
RVO是c++11的standard
06/24 07:59, 36F

06/24 08:00, 7年前 , 37F
名稱是copy elision
06/24 08:00, 37F

06/24 08:45, 7年前 , 38F
我把原PO的code改了一下 http://cpp.sh/4u437
06/24 08:45, 38F

06/24 08:46, 7年前 , 39F
28行VS報錯內容
06/24 08:46, 39F

06/24 08:46, 7年前 , 40F
'return': cannot convert from 'myClass' to 'myCl
06/24 08:46, 40F

06/24 08:46, 7年前 , 41F
ass &&'
06/24 08:46, 41F

06/24 08:47, 7年前 , 42F
Clang報錯內容
06/24 08:47, 42F

06/24 08:47, 7年前 , 43F
rvalue reference to type 'myClass' cannot bind t
06/24 08:47, 43F

06/24 08:47, 7年前 , 44F
o lvalue of type 'myClass'
06/24 08:47, 44F

06/24 10:40, 7年前 , 45F
return語句為非靜態物件名稱時,才以move取代copy,rv
06/24 10:40, 45F

06/24 10:40, 7年前 , 46F
alue ref並不是一個物件
06/24 10:40, 46F

06/24 11:06, 7年前 , 47F
還有樓上那個錯誤訊息是因為decltype(auto)是推導出my
06/24 11:06, 47F

06/24 11:06, 7年前 , 48F
Class &&
06/24 11:06, 48F

06/24 11:06, 7年前 , 49F
不是你以為的myClass
06/24 11:06, 49F

06/24 11:07, 7年前 , 50F
你可以把h函數想成這樣
06/24 11:07, 50F

06/24 11:08, 7年前 , 51F
decltype(auto) tmp = other;
06/24 11:08, 51F
感謝推文各位 稍微整理對於回答二的意見如下 參考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
文章代碼(AID): #1RBXok7y (C_and_CPP)
文章代碼(AID): #1RBXok7y (C_and_CPP)