请教一个 G++在 C++98 下为什么把 move semantics 模仿的这么熟练的问题

2017-11-28 17:47:31 +08:00
 YyYyYyy



为什么会变成这样呢......明明用的不是 C++11。明明已经关了 copy elision。两件快乐事情重合在一起。而这两份快乐,又给我带来了更多的快乐。得到的,本该是两个不同的地址......但是,为什么,会变成这样呢......

gcc 版本 6.4.0
2676 次点击
所在节点    C
24 条回复
noli
2017-11-28 17:55:38 +08:00
就算得到了相同的地址,也不代表就没有 copy 吧?
内部可能使用了 realloc 并且成功了 。
rogerchen
2017-11-28 17:56:25 +08:00
rvo 关不掉的
noli
2017-11-28 18:00:40 +08:00
@rogerchen #2 我不认为楼主的例子里满足 RVO 的条件。
YyYyYyy
2017-11-28 18:42:29 +08:00
@noli 在发这个帖子之前这问题在某 tg 群里讨论过,得到的结论也是“炸内存后原地 alloc ”。
只是无法对这种结论证伪,所以来这里问问有没有其他经验人士能否得到不同看法。
wevsty
2017-11-28 19:16:48 +08:00
看看生成的汇编代码就知道编译器是怎么处理的了。
QAPTEAWH
2017-11-28 19:18:33 +08:00
@noli 我觉得显然满足 RVO..
mooncakejs
2017-11-28 19:38:52 +08:00
@noli 我也觉得满足 rvo,因为退出函数后, 就没有代码能碰到里面的 v 对象。
换成参数传进去呢?
koebehshian
2017-11-28 20:18:50 +08:00
碰巧一样呗。函数 fun 执行完毕后,变量 v 就析构了,在堆上申请的内存也释放了,0x600000510 这个地址指向的内存没人用,恰好被 main 中的 v 内部申请内存时申请到。copy elision 应该指 v 这个对象,所以 0xffffcb50,0xffffcbb0 两个地址不同,而它们各自申请的堆内存可以恰好相同
noli
2017-11-28 20:39:58 +08:00
@QAPTEAWH @mooncakejs

请问两位怎么区分 Return Value Optimization 和 Named Return Value Optimization ?

我不认为 return v 中的 v 是纯右值,所以这里不会发生 RVO。
mooncakejs
2017-11-28 21:05:31 +08:00
@noli 我单纯的认为这是个编译器优化,因为退出 fun 后,fun 中的 v 变量已经没有任何代码可以访问,可能即使没有开-O 选项,它也可能做了这个优化。 想要测试下是不是偶然的话,在 fun 函数里,多创建几次变量,调整变量顺序再试试。
jmc891205
2017-11-28 21:44:10 +08:00
打死白学家
noli
2017-11-28 21:48:52 +08:00
@mooncakejs #10

编译器开优化也要讲基本法的。

http://en.cppreference.com/w/cpp/language/copy_elision

When a **NAMELESS** temporary, not bound to any references, would be copied or moved (since C++11) into an object of the same type (ignoring top-level cv-qualification), the copy/move (since C++11) is omitted. When that temporary is constructed, ** it is constructed directly in the storage where it would** otherwise be copied or moved (since C++11) to. When the nameless temporary is the argument of a return statement, this variant of copy elision is known as RVO, "return value optimization".

NAMELESS 的意思懂吧?就是不能绑定到任何一个变量名(否则就变成了左值了)

如果像你说的,没有东西能碰 v 就能 RVO,那编译器怎么知道 v 里面的不会被其他对象访问?
只要有变成左值的机会,就无法消除这个可能。
LPeJuN6lLsS9
2017-11-28 22:05:01 +08:00
@noli 但是这里它满足了 named rvo 的条件啊?编译器上帝视角,它当然知道这个变量出了函数作用于就要死了,它又不是参数等等
详细解释就在你摘抄的那段的上面
LPeJuN6lLsS9
2017-11-28 22:10:10 +08:00
@YyYyYyy 你自己写个类,然后做好移动方法,看看编译器是不是真的用了你的方法就行
noli
2017-11-28 22:14:42 +08:00
@hantsuki #13

同样也不满足 NRVO,因为 v 已经作为某个函数的参数适用过了。

v.push_back
v.data

经过这些调用(作为函数参数出现)之后还能 NRVO 的话,请问什么不能 NRVO ?
waruqi
2017-11-28 23:19:05 +08:00
别纠结了 用 c 吧。
fenixan2010
2017-11-28 23:25:35 +08:00
@noli 按楼主的更新不加-fno-elide-constructors 的话这里确实有用到 NRVO
LPeJuN6lLsS9
2017-11-28 23:44:50 +08:00
@noli 你想说 v.push_back 里用了 this 就算“参数”了?问题是“ which isn't a function parameter ”你读得懂吗,parameter 和 argument 不是同个意思
LPeJuN6lLsS9
2017-11-28 23:47:40 +08:00
@hantsuki #12 c++98 好像没有移动方法?犯蠢了,没用过 98
noli
2017-11-28 23:56:51 +08:00
@hantsuki #18 @fenixan2010 # 17

我同意你们的说法,v 确实不是“参数”。
是否会产生 NRVO,确实有这个可能,我之前想当然了
——虽然我觉得编译器这么推测有点危险,但确实符合 NRVO 的条件。

但是楼主的例子里面,加上那个 -fno-elide-constructors 之后应该就不会有了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/410258

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX