拷贝消除/RVO是否会引发从同一对象的拷贝或移动操作?
关于RVO是否会导致自拷贝的问题
直接给你结论:在你写的调用场景(obj = copy_maybe(true, obj);)下,不管开不开RVO/NRVO,都不会出现obj自拷贝的情况。下面给你掰扯清楚原因:
1. 当前调用的执行路径压根碰不到自拷贝
你调用时传的make_new是true,这会让copy_maybe走return SomeObject();这条分支。这条分支从头到尾都和你传入的def参数(也就是obj)没关系——它就是新建一个临时SomeObject对象返回。
开启RVO的情况
启用返回值优化(RVO)时,编译器会跳过临时对象的拷贝/移动步骤,直接把这个新对象构造到调用方为返回值预留的内存里。之后执行obj = [返回值],这是把一个全新的对象赋值给obj,和obj自身半毛钱关系都没有,自然不会有自拷贝。
没开RVO的情况
没RVO的话,函数会先造好临时对象,再把它拷贝/移动到返回值位置,最后赋值给obj——整个过程还是没用到你传入的obj,所以也不会触发自拷贝。
2. 只有这种情况才可能出现自拷贝
要是你调用的是obj = copy_maybe(false, obj);,这时候函数会走return def;的分支(也就是返回你传入的obj本身)。这时候会不会自拷贝,得看编译器有没有开命名返回值优化(NRVO):
- 没开NRVO:编译器会先把
def(也就是obj)拷贝到函数的返回值临时对象里,再把这个临时对象赋值给obj——这就触发了obj到自身的拷贝。 - 开了NRVO:有些编译器会把这个拷贝操作优化掉,直接让函数返回
obj本身,这时候赋值就变成了obj = obj;——这本质上也是自拷贝,虽然没啥意义,但C++标准是允许这种情况的。
额外提一句:编译期常量的优化
如果make_new是编译期就能确定的常量(比如你直接传true),很多编译器会直接把函数调用优化成obj = SomeObject();,连函数调用的开销都省了,这时候就更不可能涉及自拷贝了。
内容的提问来源于stack exchange,提问作者jpfx1342
相关产品推荐
相关产品推荐

