RVO、移动语义和追求最优代码的斗争

5
如果我理解正确,移动语义允许从临时的未命名对象中移动和重复使用资源。尽管在移动语义之前,返回值优化(RVO)更进一步并“窃取”整个对象以避免额外的构造函数调用和赋值/复制函数。
这对我来说似乎有点违反直觉,如果被调用的构造函数直接使用最终左值目标的地址来直接插入数据到用户需要的位置,那么它不是更快、更简单和更容易理解吗?
我的意思是,“在此位置创建此对象”似乎比“在某个地方创建此对象,然后将其复制到其正确的位置”更直观。

@Angew - 在这种情况下,只有 f() 会直接返回到 a 的地址,其余的都会返回到调用 f() 时使用的临时对象的地址。毕竟,唯一的赋值是从 f() 的返回值到 a - user2341104
这个(密切)回答了同样的问题:“如果我们已经有RVO,移动语义提供了什么优化?” - https://dev59.com/-2445IYBdhLWcg3wGmk6 - SChepurin
@Angew - 是的,最优的方法是将函数的返回值直接放置在需要它们的位置上,对于内部调用来说,这将直接放置在参数槽中,对于 f() 来说,它将位于 a 的位置。毕竟,重点是消除复制/赋值。但用户不必显式提供返回地址,编译器可以处理,对于 lvalue 和 rvalue 作为 lvalue 槽。毕竟,即使用户想要指定未命名临时变量的地址,他也无法指定。 - user2341104
2
如果您对编译器提供地址感到满意,那么我可能误解了问题。RVO确切地说是“在此位置创建此对象”。那么您实际上想问什么? - Angew is no longer proud of SO
@dornhege - 这很简单,没有要构造的对象 = 无名临时对象。 - user2341104
显示剩余5条评论
1个回答

7

是的,这有点反直觉。启用复制省略后,构造函数的所有副作用也被省略。

#include <iostream>

struct X {
    X() { std::cout << "Construct" << std::endl; }
    X(X&&) { std::cout << "Move" << std::endl; }
    ~X() { std::cout << "Destruct" << std::endl; };
};

X f() { return X(); }

int main()
{
    X x(f());
    return 0;
}

复制省略: g++ -std=c++11 src-test/main.cc

Construct
Destruct

禁止拷贝省略:g++ -std=c++11 -fno-elide-constructors src-test/main.cc

Construct
Move
Destruct
Move
Destruct
Destruct

编译器了解程序/库构建的硬件,可以应用(可选的)复制省略。C++语言本身不知道硬件特定的返回机制。因此,在这种情况下无法构造某个地址。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接