作者a58524andy (a58524andy)
看板C_and_CPP
标题[问题] 关於c++11 ctor行为
时间Sat Jun 23 18:10:49 2018
开发平台(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://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1529748654.A.1FC.html
1F:→ bluesoul: 1你的理解是对的 06/23 18:50
2F:嘘 KanzakiHAria: 缩写看得很不舒服 Constructor就打完整 06/23 20:25
3F:→ KanzakiHAria: 一个物件实体化第一次的=不会使用operator= 06/23 20:26
4F:→ KanzakiHAria: 所以第一次=会呼叫constructor 06/23 20:26
5F:→ KanzakiHAria: move可能慢的原因为复制成本太低 06/23 20:27
6F:→ KanzakiHAria: std::move是一个function 所以还是会有离开回来 06/23 20:28
7F:→ KanzakiHAria: 例如int 型态还特地调用move就会造成过多的搬移成本 06/23 20:28
8F:→ KanzakiHAria: move最值得使用的情境为:当一个需要deep copy的物 06/23 20:29
9F:→ KanzakiHAria: 件要用来初始化别人,这时候move就不需要copy 06/23 20:30
10F:→ KanzakiHAria: 但是如果这个东西之後还要继续用就无法使用move 06/23 20:30
11F:→ KanzakiHAria: 那只好回到使用copy 06/23 20:30
12F:→ KanzakiHAria: 简单说可以想像类似搬进去function的scope 06/23 20:32
13F:→ KanzakiHAria: 离开function 的时候这个东西会destruct 06/23 20:32
14F:推 legendmtg: ctor是很惯用的缩写吧 06/23 20:37
15F:→ chchwy: 并没有什麽实体化第一次不呼叫operator=的规则 06/23 20:41
16F:→ chchwy: 那是因为编译器开了RVO 你把RVO关掉就可以看见正确行为 06/23 20:42
17F:→ 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
18F:→ Feis: 名字 06/24 01:09
19F:推 BlazarArc: ctor很常见的缩写 06/24 01:19
20F:→ Feis: case 2. reference (cp), std::move (mv) 06/24 01:25
21F:推 steve1012: ctor 很ok的 06/24 03:46
22F:推 KanzakiHAria: 你在讲什麽?constructor的return是void哪有甚麽回传 06/24 06:20
23F:→ KanzakiHAria: function return都是rvalue 建构子也是 06/24 06:27
24F:→ KanzakiHAria: 我终於看懂你的问题了...... 06/24 06:45
25F:→ KanzakiHAria: 因为你的g不是回传reference type 06/24 06:45
26F:→ KanzakiHAria: 当然不会动到reference的constructor阿...... 06/24 06:46
27F:→ KanzakiHAria: 你的问题是连最基本的三种呼叫和回传都没搞懂 06/24 06:48
28F:→ KanzakiHAria: call by value, call by address,call by reference 06/24 06:48
30F:→ firose: 感觉他是 xvalue 应该能安全 move 才对 06/24 07:06
31F:推 KanzakiHAria: 因为在function内scope是lvalue reference 06/24 07:34
32F:→ KanzakiHAria: 也就是原PO的22行还要使用move才会cast回rvalue ref 06/24 07:37
33F:→ KanzakiHAria: erence 06/24 07:37
34F:→ firose: 问题是 case1 也是 lvalue 就可以 move 06/24 07:53
35F:推 KanzakiHAria: 所以是RVO关不掉? 06/24 07:58
36F:→ KanzakiHAria: RVO是c++11的standard 06/24 07:59
37F:→ KanzakiHAria: 名称是copy elision 06/24 08:00
39F:→ KanzakiHAria: 28行VS报错内容 06/24 08:46
40F:→ KanzakiHAria: 'return': cannot convert from 'myClass' to 'myCl 06/24 08:46
41F:→ KanzakiHAria: ass &&' 06/24 08:46
42F:→ KanzakiHAria: Clang报错内容 06/24 08:47
43F:→ KanzakiHAria: rvalue reference to type 'myClass' cannot bind t 06/24 08:47
44F:→ KanzakiHAria: o lvalue of type 'myClass' 06/24 08:47
45F:→ loveflames: return语句为非静态物件名称时,才以move取代copy,rv 06/24 10:40
46F:→ loveflames: alue ref并不是一个物件 06/24 10:40
47F:→ loveflames: 还有楼上那个错误讯息是因为decltype(auto)是推导出my 06/24 11:06
48F:→ loveflames: Class && 06/24 11:06
49F:→ loveflames: 不是你以为的myClass 06/24 11:06
50F:→ loveflames: 你可以把h函数想成这样 06/24 11:07
51F:→ 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