1
noli 2017-11-28 17:55:38 +08:00
就算得到了相同的地址,也不代表就没有 copy 吧?
内部可能使用了 realloc 并且成功了 。 |
2
rogerchen 2017-11-28 17:56:25 +08:00 via iPhone
rvo 关不掉的
|
4
YyYyYyy OP @noli 在发这个帖子之前这问题在某 tg 群里讨论过,得到的结论也是“炸内存后原地 alloc ”。
只是无法对这种结论证伪,所以来这里问问有没有其他经验人士能否得到不同看法。 |
5
wevsty 2017-11-28 19:16:48 +08:00
看看生成的汇编代码就知道编译器是怎么处理的了。
|
7
mooncakejs 2017-11-28 19:38:52 +08:00
@noli 我也觉得满足 rvo,因为退出函数后, 就没有代码能碰到里面的 v 对象。
换成参数传进去呢? |
8
koebehshian 2017-11-28 20:18:50 +08:00 1
碰巧一样呗。函数 fun 执行完毕后,变量 v 就析构了,在堆上申请的内存也释放了,0x600000510 这个地址指向的内存没人用,恰好被 main 中的 v 内部申请内存时申请到。copy elision 应该指 v 这个对象,所以 0xffffcb50,0xffffcbb0 两个地址不同,而它们各自申请的堆内存可以恰好相同
|
9
noli 2017-11-28 20:39:58 +08:00
@QAPTEAWH @mooncakejs
请问两位怎么区分 Return Value Optimization 和 Named Return Value Optimization ? 我不认为 return v 中的 v 是纯右值,所以这里不会发生 RVO。 |
10
mooncakejs 2017-11-28 21:05:31 +08:00
@noli 我单纯的认为这是个编译器优化,因为退出 fun 后,fun 中的 v 变量已经没有任何代码可以访问,可能即使没有开-O 选项,它也可能做了这个优化。 想要测试下是不是偶然的话,在 fun 函数里,多创建几次变量,调整变量顺序再试试。
|
11
jmc891205 2017-11-28 21:44:10 +08:00 1
打死白学家
|
12
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 里面的不会被其他对象访问? 只要有变成左值的机会,就无法消除这个可能。 |
13
LPeJuN6lLsS9 2017-11-28 22:05:01 +08:00
@noli 但是这里它满足了 named rvo 的条件啊?编译器上帝视角,它当然知道这个变量出了函数作用于就要死了,它又不是参数等等
详细解释就在你摘抄的那段的上面 |
14
LPeJuN6lLsS9 2017-11-28 22:10:10 +08:00
@YyYyYyy 你自己写个类,然后做好移动方法,看看编译器是不是真的用了你的方法就行
|
15
noli 2017-11-28 22:14:42 +08:00
@hantsuki #13
同样也不满足 NRVO,因为 v 已经作为某个函数的参数适用过了。 v.push_back v.data 经过这些调用(作为函数参数出现)之后还能 NRVO 的话,请问什么不能 NRVO ? |
16
waruqi 2017-11-28 23:19:05 +08:00 via Android
别纠结了 用 c 吧。
|
17
fenixan2010 2017-11-28 23:25:35 +08:00
@noli 按楼主的更新不加-fno-elide-constructors 的话这里确实有用到 NRVO
|
18
LPeJuN6lLsS9 2017-11-28 23:44:50 +08:00 1
@noli 你想说 v.push_back 里用了 this 就算“参数”了?问题是“ which isn't a function parameter ”你读得懂吗,parameter 和 argument 不是同个意思
|
19
LPeJuN6lLsS9 2017-11-28 23:47:40 +08:00
@hantsuki #12 c++98 好像没有移动方法?犯蠢了,没用过 98
|
20
noli 2017-11-28 23:56:51 +08:00
@hantsuki #18 @fenixan2010 # 17
我同意你们的说法,v 确实不是“参数”。 是否会产生 NRVO,确实有这个可能,我之前想当然了 ——虽然我觉得编译器这么推测有点危险,但确实符合 NRVO 的条件。 但是楼主的例子里面,加上那个 -fno-elide-constructors 之后应该就不会有了。 |
21
ccsexyz 2017-11-29 00:01:12 +08:00
我认为是这样的,这里 v = func() 有两次拷贝构造函数 vector(const vector &)。
func:v --> tmp:v 拷贝构造 --> func:v 析构 --> main:v 拷贝构造(分配的存储区域刚好和 func:v 存储区域一致) --> tmp:v 析构 |
22
LPeJuN6lLsS9 2017-11-29 00:08:14 +08:00 via Android
@noli 就是想反驳一下你说的不满足 nrvo。楼主那是咋回事我还没去想
用 msvc2017 开 release 模式做了个简单实验,也是这样调用了一个方法后才返回,确实没有移动和复制构造。 为啥会觉得危险呢,我觉得 nrvo 大前提是一个自动变量,这就很安全了 |
23
lrxiao 2017-11-29 02:17:25 +08:00
NRVO 关不掉
符合 NRVO 但是 asm 是正常的调用两次 copy ctor fun 中和 main 中 data()最后同一地址 但是临时对象不是 |
24
gnaggnoyil 2017-11-29 05:49:19 +08:00
C++98 我不熟,不过我想提醒那些说 NRVO 的人,`std::vector<int> v=fun()`还需要一次构造过程呢.
|